diff options
| author | Laurenz <laurmaedje@gmail.com> | 2024-04-13 10:39:45 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2024-05-17 14:27:59 +0200 |
| commit | e039552f9d7bb49da8dafe7a83b87a08202eb30f (patch) | |
| tree | 264b461722f758d85217da804550620cd74b4f9e /tests | |
| parent | 8e025c9cdfbb0a5dae536aafc27b5e19eeac1810 (diff) | |
Better test runner (#3922)
Diffstat (limited to 'tests')
1948 files changed, 19741 insertions, 20020 deletions
diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 1f650c97..62e7a493 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -6,29 +6,29 @@ authors = { workspace = true } edition = { workspace = true } publish = false -[dev-dependencies] +[[test]] +name = "tests" +path = "src/tests.rs" +harness = false + +[dependencies] typst = { workspace = true } typst-assets = { workspace = true, features = ["fonts"] } typst-dev-assets = { workspace = true } typst-pdf = { workspace = true } typst-render = { workspace = true } typst-svg = { workspace = true } -typst-ide = { workspace = true } clap = { workspace = true } comemo = { workspace = true } ecow = { workspace = true } once_cell = { workspace = true } oxipng = { workspace = true } +parking_lot = { workspace = true } rayon = { workspace = true } tiny-skia = { workspace = true } ttf-parser = { workspace = true } unscanny = { workspace = true } walkdir = { workspace = true } -[[test]] -name = "tests" -path = "src/tests.rs" -harness = false - [lints] workspace = true diff --git a/tests/README.md b/tests/README.md index 68b72f2d..6cc79217 100644 --- a/tests/README.md +++ b/tests/README.md @@ -3,13 +3,10 @@ ## Directory structure Top level directory structure: - `src`: Testing code. -- `typ`: Input files. The tests in `compiler` specifically test the compiler - while the others test the standard library (but also the compiler - indirectly). +- `suite`: Input files. Mostly organize in parallel to the code. - `ref`: Reference images which the output is compared with to determine whether a test passed or failed. -- `png`: PNG files produced by tests. -- `pdf`: PDF files produced by tests. +- `store`: Store for PNG, PDF, and SVG output files produced by the tests. ## Running the tests Running all tests (including unit tests): @@ -37,11 +34,6 @@ Running a test with the exact filename `page.typ`. testit --exact page.typ ``` -Debug-printing the layout trees for all executed tests. -```bash -testit --debug empty.typ -``` - To make the integration tests go faster they don't generate PDFs by default. Pass the `--pdf` flag to generate those. Mind that PDFs are not tested automatically at the moment, so you should always check the output manually when @@ -50,18 +42,48 @@ making changes. testit --pdf ``` -## Update expected images +## Writing tests +The syntax for an individual test is `--- {name} ---` followed by some Typst +code that should be tested. The name must be globally unique in the test suite, +so that tests can be easily migrated across files. + +There are, broadly speaking, three kinds of tests: + +- Tests that just ensure that the code runs successfully: Those typically make + use of `test` or `assert.eq` (both are very similar, `test` is just shorter) + to ensure certain properties hold when executing the Typst code. + +- Tests that ensure the code fails with a particular error: Those have inline + annotations like `// Error: 2-7 thing was wrong`. An annotation can be + either an "Error", a "Warning", or a "Hint". The range designates where + in the next non-comment line the error is and after it follows the message. + If you the error is in a line further below, you can also write ranges like + `3:2-3:7` to indicate the 2-7 column in the 3rd non-comment line. + +- Tests that ensure certain visual output is produced: Those render the result + of the test with the `typst-render` crate and compare against a reference + image stored in the repository. The test runner automatically detects whether + a test has visual output and requires a reference image in this case. + + To prevent bloat, it is important that the test images are kept as small as + possible. To that effect, the test runner enforces a maximum size of 20 KiB. + If truly necessary, this limit can however be lifted by adding `// LARGE` as + the first line of a test. + +If you have the choice between writing a test using assertions or using +reference images, prefer assertions. This makes the test easier to understand +in isolation and prevents bloat due to images. + +## Updating reference images If you created a new test or fixed a bug in an existing test, you need to update -the reference image used for comparison. For this, you can use the -`UPDATE_EXPECT` environment variable or the `--update` flag: +the reference image used for comparison. For this, you can use the `--update` +flag: ```bash testit mytest --update ``` If you use the VS Code test helper extension (see the `tools` folder), you can -alternatively use the checkmark button to update the reference image. In that -case you should also install `oxipng` on your system so that the test helper -can optimize the reference images. +alternatively use the save button to update the reference image. ## Making an alias If you want to have a quicker way to run the tests, consider adding a shortcut diff --git a/tests/ref/align-center-in-flow.png b/tests/ref/align-center-in-flow.png Binary files differnew file mode 100644 index 00000000..ecfe49dc --- /dev/null +++ b/tests/ref/align-center-in-flow.png diff --git a/tests/ref/align-in-stack.png b/tests/ref/align-in-stack.png Binary files differnew file mode 100644 index 00000000..556721ab --- /dev/null +++ b/tests/ref/align-in-stack.png diff --git a/tests/ref/align-right.png b/tests/ref/align-right.png Binary files differnew file mode 100644 index 00000000..edab8851 --- /dev/null +++ b/tests/ref/align-right.png diff --git a/tests/ref/align-start-and-end.png b/tests/ref/align-start-and-end.png Binary files differnew file mode 100644 index 00000000..cf3faeae --- /dev/null +++ b/tests/ref/align-start-and-end.png diff --git a/tests/ref/array-basic-syntax.png b/tests/ref/array-basic-syntax.png Binary files differnew file mode 100644 index 00000000..6eb95305 --- /dev/null +++ b/tests/ref/array-basic-syntax.png diff --git a/tests/ref/array-insert-and-remove.png b/tests/ref/array-insert-and-remove.png Binary files differnew file mode 100644 index 00000000..ea4b8cf2 --- /dev/null +++ b/tests/ref/array-insert-and-remove.png diff --git a/tests/ref/array-join-content.png b/tests/ref/array-join-content.png Binary files differnew file mode 100644 index 00000000..4d08142e --- /dev/null +++ b/tests/ref/array-join-content.png diff --git a/tests/ref/baseline-box.png b/tests/ref/baseline-box.png Binary files differnew file mode 100644 index 00000000..8d7627c6 --- /dev/null +++ b/tests/ref/baseline-box.png diff --git a/tests/ref/baseline-text.png b/tests/ref/baseline-text.png Binary files differnew file mode 100644 index 00000000..72beac79 --- /dev/null +++ b/tests/ref/baseline-text.png diff --git a/tests/ref/bibliography-basic.png b/tests/ref/bibliography-basic.png Binary files differnew file mode 100644 index 00000000..eeb773bf --- /dev/null +++ b/tests/ref/bibliography-basic.png diff --git a/tests/ref/bibliography-before-content.png b/tests/ref/bibliography-before-content.png Binary files differnew file mode 100644 index 00000000..806daa08 --- /dev/null +++ b/tests/ref/bibliography-before-content.png diff --git a/tests/ref/bibliography-full.png b/tests/ref/bibliography-full.png Binary files differnew file mode 100644 index 00000000..1da15d16 --- /dev/null +++ b/tests/ref/bibliography-full.png diff --git a/tests/ref/bibliography-math.png b/tests/ref/bibliography-math.png Binary files differnew file mode 100644 index 00000000..3fc36efc --- /dev/null +++ b/tests/ref/bibliography-math.png diff --git a/tests/ref/bibliography-multiple-files.png b/tests/ref/bibliography-multiple-files.png Binary files differnew file mode 100644 index 00000000..1293ba22 --- /dev/null +++ b/tests/ref/bibliography-multiple-files.png diff --git a/tests/ref/bibliography-ordering.png b/tests/ref/bibliography-ordering.png Binary files differnew file mode 100644 index 00000000..b1e14c9a --- /dev/null +++ b/tests/ref/bibliography-ordering.png diff --git a/tests/ref/bidi-consecutive-embedded-ltr-runs.png b/tests/ref/bidi-consecutive-embedded-ltr-runs.png Binary files differnew file mode 100644 index 00000000..dbaaff07 --- /dev/null +++ b/tests/ref/bidi-consecutive-embedded-ltr-runs.png diff --git a/tests/ref/bidi-consecutive-embedded-rtl-runs.png b/tests/ref/bidi-consecutive-embedded-rtl-runs.png Binary files differnew file mode 100644 index 00000000..4cf62d3e --- /dev/null +++ b/tests/ref/bidi-consecutive-embedded-rtl-runs.png diff --git a/tests/ref/bidi-en-he-top-level.png b/tests/ref/bidi-en-he-top-level.png Binary files differnew file mode 100644 index 00000000..abab54f4 --- /dev/null +++ b/tests/ref/bidi-en-he-top-level.png diff --git a/tests/ref/bidi-explicit-dir.png b/tests/ref/bidi-explicit-dir.png Binary files differnew file mode 100644 index 00000000..8b813be0 --- /dev/null +++ b/tests/ref/bidi-explicit-dir.png diff --git a/tests/ref/bidi-manual-linebreak.png b/tests/ref/bidi-manual-linebreak.png Binary files differnew file mode 100644 index 00000000..4d0eb6f8 --- /dev/null +++ b/tests/ref/bidi-manual-linebreak.png diff --git a/tests/ref/bidi-nesting.png b/tests/ref/bidi-nesting.png Binary files differnew file mode 100644 index 00000000..e18d6c0a --- /dev/null +++ b/tests/ref/bidi-nesting.png diff --git a/tests/ref/bidi-obj.png b/tests/ref/bidi-obj.png Binary files differnew file mode 100644 index 00000000..8cc41528 --- /dev/null +++ b/tests/ref/bidi-obj.png diff --git a/tests/ref/bidi-raw.png b/tests/ref/bidi-raw.png Binary files differnew file mode 100644 index 00000000..24503ee9 --- /dev/null +++ b/tests/ref/bidi-raw.png diff --git a/tests/ref/bidi-spacing.png b/tests/ref/bidi-spacing.png Binary files differnew file mode 100644 index 00000000..44ede76f --- /dev/null +++ b/tests/ref/bidi-spacing.png diff --git a/tests/ref/bidi-whitespace-reset.png b/tests/ref/bidi-whitespace-reset.png Binary files differnew file mode 100644 index 00000000..7d64012f --- /dev/null +++ b/tests/ref/bidi-whitespace-reset.png diff --git a/tests/ref/block-box-fill.png b/tests/ref/block-box-fill.png Binary files differnew file mode 100644 index 00000000..fe4f7258 --- /dev/null +++ b/tests/ref/block-box-fill.png diff --git a/tests/ref/block-clip-svg-glyphs.png b/tests/ref/block-clip-svg-glyphs.png Binary files differnew file mode 100644 index 00000000..d8db5b61 --- /dev/null +++ b/tests/ref/block-clip-svg-glyphs.png diff --git a/tests/ref/block-clip-text.png b/tests/ref/block-clip-text.png Binary files differnew file mode 100644 index 00000000..7cd86ddb --- /dev/null +++ b/tests/ref/block-clip-text.png diff --git a/tests/ref/block-clipping-multiple-pages.png b/tests/ref/block-clipping-multiple-pages.png Binary files differnew file mode 100644 index 00000000..9c9aa89b --- /dev/null +++ b/tests/ref/block-clipping-multiple-pages.png diff --git a/tests/ref/block-fixed-height.png b/tests/ref/block-fixed-height.png Binary files differnew file mode 100644 index 00000000..95c3be1e --- /dev/null +++ b/tests/ref/block-fixed-height.png diff --git a/tests/ref/block-multiple-pages.png b/tests/ref/block-multiple-pages.png Binary files differnew file mode 100644 index 00000000..c2f192bd --- /dev/null +++ b/tests/ref/block-multiple-pages.png diff --git a/tests/ref/block-sizing.png b/tests/ref/block-sizing.png Binary files differnew file mode 100644 index 00000000..76cb04df --- /dev/null +++ b/tests/ref/block-sizing.png diff --git a/tests/ref/block-spacing-basic.png b/tests/ref/block-spacing-basic.png Binary files differnew file mode 100644 index 00000000..875410ac --- /dev/null +++ b/tests/ref/block-spacing-basic.png diff --git a/tests/ref/block-spacing-collapse-text-style.png b/tests/ref/block-spacing-collapse-text-style.png Binary files differnew file mode 100644 index 00000000..6c631457 --- /dev/null +++ b/tests/ref/block-spacing-collapse-text-style.png diff --git a/tests/ref/block-spacing-maximum.png b/tests/ref/block-spacing-maximum.png Binary files differnew file mode 100644 index 00000000..755b1cc3 --- /dev/null +++ b/tests/ref/block-spacing-maximum.png diff --git a/tests/ref/block-spacing-table.png b/tests/ref/block-spacing-table.png Binary files differnew file mode 100644 index 00000000..1591acb7 --- /dev/null +++ b/tests/ref/block-spacing-table.png diff --git a/tests/ref/box-clip-radius-without-stroke.png b/tests/ref/box-clip-radius-without-stroke.png Binary files differnew file mode 100644 index 00000000..12137358 --- /dev/null +++ b/tests/ref/box-clip-radius-without-stroke.png diff --git a/tests/ref/box-clip-radius.png b/tests/ref/box-clip-radius.png Binary files differnew file mode 100644 index 00000000..da20fa5b --- /dev/null +++ b/tests/ref/box-clip-radius.png diff --git a/tests/ref/box-clip-rect.png b/tests/ref/box-clip-rect.png Binary files differnew file mode 100644 index 00000000..49a4e4ab --- /dev/null +++ b/tests/ref/box-clip-rect.png diff --git a/tests/ref/box-layoutable-child.png b/tests/ref/box-layoutable-child.png Binary files differnew file mode 100644 index 00000000..a1960a24 --- /dev/null +++ b/tests/ref/box-layoutable-child.png diff --git a/tests/ref/box-width-fr.png b/tests/ref/box-width-fr.png Binary files differnew file mode 100644 index 00000000..30d48163 --- /dev/null +++ b/tests/ref/box-width-fr.png diff --git a/tests/ref/box.png b/tests/ref/box.png Binary files differnew file mode 100644 index 00000000..fde288a8 --- /dev/null +++ b/tests/ref/box.png diff --git a/tests/ref/bugs/1050-terms-indent.png b/tests/ref/bugs/1050-terms-indent.png Binary files differdeleted file mode 100644 index 58a7feae..00000000 --- a/tests/ref/bugs/1050-terms-indent.png +++ /dev/null diff --git a/tests/ref/bugs/1240-stack-fr.png b/tests/ref/bugs/1240-stack-fr.png Binary files differdeleted file mode 100644 index 29df5d44..00000000 --- a/tests/ref/bugs/1240-stack-fr.png +++ /dev/null diff --git a/tests/ref/bugs/1597-cite-footnote.png b/tests/ref/bugs/1597-cite-footnote.png Binary files differdeleted file mode 100644 index c2e219f2..00000000 --- a/tests/ref/bugs/1597-cite-footnote.png +++ /dev/null diff --git a/tests/ref/bugs/2044-invalid-parsed-ident.png b/tests/ref/bugs/2044-invalid-parsed-ident.png Binary files differdeleted file mode 100644 index 327150e7..00000000 --- a/tests/ref/bugs/2044-invalid-parsed-ident.png +++ /dev/null diff --git a/tests/ref/bugs/2105-linebreak-tofu.png b/tests/ref/bugs/2105-linebreak-tofu.png Binary files differdeleted file mode 100644 index 78f937eb..00000000 --- a/tests/ref/bugs/2105-linebreak-tofu.png +++ /dev/null diff --git a/tests/ref/bugs/2595-float-overlap.png b/tests/ref/bugs/2595-float-overlap.png Binary files differdeleted file mode 100644 index 6d8eaf94..00000000 --- a/tests/ref/bugs/2595-float-overlap.png +++ /dev/null diff --git a/tests/ref/bugs/2650-cjk-latin-spacing-meta.png b/tests/ref/bugs/2650-cjk-latin-spacing-meta.png Binary files differdeleted file mode 100644 index 35ff0e62..00000000 --- a/tests/ref/bugs/2650-cjk-latin-spacing-meta.png +++ /dev/null diff --git a/tests/ref/bugs/2715-float-order.png b/tests/ref/bugs/2715-float-order.png Binary files differdeleted file mode 100644 index 0a4f8812..00000000 --- a/tests/ref/bugs/2715-float-order.png +++ /dev/null diff --git a/tests/ref/bugs/3082-chinese-punctuation.png b/tests/ref/bugs/3082-chinese-punctuation.png Binary files differdeleted file mode 100644 index c187d495..00000000 --- a/tests/ref/bugs/3082-chinese-punctuation.png +++ /dev/null diff --git a/tests/ref/bugs/3641-float-loop.png b/tests/ref/bugs/3641-float-loop.png Binary files differdeleted file mode 100644 index 092b2ff5..00000000 --- a/tests/ref/bugs/3641-float-loop.png +++ /dev/null diff --git a/tests/ref/bugs/3650-italic-equation.png b/tests/ref/bugs/3650-italic-equation.png Binary files differdeleted file mode 100644 index 41f071ab..00000000 --- a/tests/ref/bugs/3650-italic-equation.png +++ /dev/null diff --git a/tests/ref/bugs/3658-math-size.png b/tests/ref/bugs/3658-math-size.png Binary files differdeleted file mode 100644 index 94c8d388..00000000 --- a/tests/ref/bugs/3658-math-size.png +++ /dev/null diff --git a/tests/ref/bugs/3662-pdf-smartquotes.png b/tests/ref/bugs/3662-pdf-smartquotes.png Binary files differdeleted file mode 100644 index c272a8ff..00000000 --- a/tests/ref/bugs/3662-pdf-smartquotes.png +++ /dev/null diff --git a/tests/ref/bugs/3700-deformed-stroke.png b/tests/ref/bugs/3700-deformed-stroke.png Binary files differdeleted file mode 100644 index f1db2836..00000000 --- a/tests/ref/bugs/3700-deformed-stroke.png +++ /dev/null diff --git a/tests/ref/bugs/3841-tabs-in-raw-typ-code.png b/tests/ref/bugs/3841-tabs-in-raw-typ-code.png Binary files differdeleted file mode 100644 index 37dab136..00000000 --- a/tests/ref/bugs/3841-tabs-in-raw-typ-code.png +++ /dev/null diff --git a/tests/ref/bugs/870-image-rotation.png b/tests/ref/bugs/870-image-rotation.png Binary files differdeleted file mode 100644 index 83d9267d..00000000 --- a/tests/ref/bugs/870-image-rotation.png +++ /dev/null diff --git a/tests/ref/bugs/args-sink.png b/tests/ref/bugs/args-sink.png Binary files differdeleted file mode 100644 index 564c59a2..00000000 --- a/tests/ref/bugs/args-sink.png +++ /dev/null diff --git a/tests/ref/bugs/bibliography-math.png b/tests/ref/bugs/bibliography-math.png Binary files differdeleted file mode 100644 index 0ab308dc..00000000 --- a/tests/ref/bugs/bibliography-math.png +++ /dev/null diff --git a/tests/ref/bugs/bidi-tofus.png b/tests/ref/bugs/bidi-tofus.png Binary files differdeleted file mode 100644 index 1b7a7d8b..00000000 --- a/tests/ref/bugs/bidi-tofus.png +++ /dev/null diff --git a/tests/ref/bugs/block-width-box.png b/tests/ref/bugs/block-width-box.png Binary files differdeleted file mode 100644 index 9cb27a5d..00000000 --- a/tests/ref/bugs/block-width-box.png +++ /dev/null diff --git a/tests/ref/bugs/cite-locate.png b/tests/ref/bugs/cite-locate.png Binary files differdeleted file mode 100644 index bd31df7d..00000000 --- a/tests/ref/bugs/cite-locate.png +++ /dev/null diff --git a/tests/ref/bugs/cite-show-set.png b/tests/ref/bugs/cite-show-set.png Binary files differdeleted file mode 100644 index 566186a4..00000000 --- a/tests/ref/bugs/cite-show-set.png +++ /dev/null diff --git a/tests/ref/bugs/clamp-panic.png b/tests/ref/bugs/clamp-panic.png Binary files differdeleted file mode 100644 index c0c4912e..00000000 --- a/tests/ref/bugs/clamp-panic.png +++ /dev/null diff --git a/tests/ref/bugs/columns-1.png b/tests/ref/bugs/columns-1.png Binary files differdeleted file mode 100644 index 4b462b60..00000000 --- a/tests/ref/bugs/columns-1.png +++ /dev/null diff --git a/tests/ref/bugs/emoji-linebreak.png b/tests/ref/bugs/emoji-linebreak.png Binary files differdeleted file mode 100644 index 6944233d..00000000 --- a/tests/ref/bugs/emoji-linebreak.png +++ /dev/null diff --git a/tests/ref/bugs/flow-1.png b/tests/ref/bugs/flow-1.png Binary files differdeleted file mode 100644 index 662a7b14..00000000 --- a/tests/ref/bugs/flow-1.png +++ /dev/null diff --git a/tests/ref/bugs/flow-2.png b/tests/ref/bugs/flow-2.png Binary files differdeleted file mode 100644 index c7ece308..00000000 --- a/tests/ref/bugs/flow-2.png +++ /dev/null diff --git a/tests/ref/bugs/flow-3.png b/tests/ref/bugs/flow-3.png Binary files differdeleted file mode 100644 index 25acc06d..00000000 --- a/tests/ref/bugs/flow-3.png +++ /dev/null diff --git a/tests/ref/bugs/flow-4.png b/tests/ref/bugs/flow-4.png Binary files differdeleted file mode 100644 index 2adcbe15..00000000 --- a/tests/ref/bugs/flow-4.png +++ /dev/null diff --git a/tests/ref/bugs/flow-5.png b/tests/ref/bugs/flow-5.png Binary files differdeleted file mode 100644 index 648c8c44..00000000 --- a/tests/ref/bugs/flow-5.png +++ /dev/null diff --git a/tests/ref/bugs/fold-vector.png b/tests/ref/bugs/fold-vector.png Binary files differdeleted file mode 100644 index d8503a8e..00000000 --- a/tests/ref/bugs/fold-vector.png +++ /dev/null diff --git a/tests/ref/bugs/footnote-keep-multiple.png b/tests/ref/bugs/footnote-keep-multiple.png Binary files differdeleted file mode 100644 index f3b67a74..00000000 --- a/tests/ref/bugs/footnote-keep-multiple.png +++ /dev/null diff --git a/tests/ref/bugs/footnote-list.png b/tests/ref/bugs/footnote-list.png Binary files differdeleted file mode 100644 index 1b56f227..00000000 --- a/tests/ref/bugs/footnote-list.png +++ /dev/null diff --git a/tests/ref/bugs/gradient-cmyk-encode.png b/tests/ref/bugs/gradient-cmyk-encode.png Binary files differdeleted file mode 100644 index 5002442f..00000000 --- a/tests/ref/bugs/gradient-cmyk-encode.png +++ /dev/null diff --git a/tests/ref/bugs/grid-1.png b/tests/ref/bugs/grid-1.png Binary files differdeleted file mode 100644 index f60ad7f4..00000000 --- a/tests/ref/bugs/grid-1.png +++ /dev/null diff --git a/tests/ref/bugs/grid-2.png b/tests/ref/bugs/grid-2.png Binary files differdeleted file mode 100644 index 882e0d6a..00000000 --- a/tests/ref/bugs/grid-2.png +++ /dev/null diff --git a/tests/ref/bugs/grid-3.png b/tests/ref/bugs/grid-3.png Binary files differdeleted file mode 100644 index 6b5ae649..00000000 --- a/tests/ref/bugs/grid-3.png +++ /dev/null diff --git a/tests/ref/bugs/grid-4.png b/tests/ref/bugs/grid-4.png Binary files differdeleted file mode 100644 index 475f561e..00000000 --- a/tests/ref/bugs/grid-4.png +++ /dev/null diff --git a/tests/ref/bugs/hide-meta.png b/tests/ref/bugs/hide-meta.png Binary files differdeleted file mode 100644 index 76b4671a..00000000 --- a/tests/ref/bugs/hide-meta.png +++ /dev/null diff --git a/tests/ref/bugs/justify-hanging-indent.png b/tests/ref/bugs/justify-hanging-indent.png Binary files differdeleted file mode 100644 index 015cc44e..00000000 --- a/tests/ref/bugs/justify-hanging-indent.png +++ /dev/null diff --git a/tests/ref/bugs/line-align.png b/tests/ref/bugs/line-align.png Binary files differdeleted file mode 100644 index 1117ed6b..00000000 --- a/tests/ref/bugs/line-align.png +++ /dev/null diff --git a/tests/ref/bugs/linebreak-no-justifiables.png b/tests/ref/bugs/linebreak-no-justifiables.png Binary files differdeleted file mode 100644 index 3f934592..00000000 --- a/tests/ref/bugs/linebreak-no-justifiables.png +++ /dev/null diff --git a/tests/ref/bugs/mat-aug-color.png b/tests/ref/bugs/mat-aug-color.png Binary files differdeleted file mode 100644 index 472c1968..00000000 --- a/tests/ref/bugs/mat-aug-color.png +++ /dev/null diff --git a/tests/ref/bugs/math-eval.png b/tests/ref/bugs/math-eval.png Binary files differdeleted file mode 100644 index b673e503..00000000 --- a/tests/ref/bugs/math-eval.png +++ /dev/null diff --git a/tests/ref/bugs/math-hide.png b/tests/ref/bugs/math-hide.png Binary files differdeleted file mode 100644 index 7ac5d2f1..00000000 --- a/tests/ref/bugs/math-hide.png +++ /dev/null diff --git a/tests/ref/bugs/math-number-spacing.png b/tests/ref/bugs/math-number-spacing.png Binary files differdeleted file mode 100644 index 5ec65df3..00000000 --- a/tests/ref/bugs/math-number-spacing.png +++ /dev/null diff --git a/tests/ref/bugs/math-realize.png b/tests/ref/bugs/math-realize.png Binary files differdeleted file mode 100644 index e972e099..00000000 --- a/tests/ref/bugs/math-realize.png +++ /dev/null diff --git a/tests/ref/bugs/math-shift.png b/tests/ref/bugs/math-shift.png Binary files differdeleted file mode 100644 index d6a2ef3b..00000000 --- a/tests/ref/bugs/math-shift.png +++ /dev/null diff --git a/tests/ref/bugs/math-text-break.png b/tests/ref/bugs/math-text-break.png Binary files differdeleted file mode 100644 index 768ca65f..00000000 --- a/tests/ref/bugs/math-text-break.png +++ /dev/null diff --git a/tests/ref/bugs/new-cm-svg.png b/tests/ref/bugs/new-cm-svg.png Binary files differdeleted file mode 100644 index d75a6dbb..00000000 --- a/tests/ref/bugs/new-cm-svg.png +++ /dev/null diff --git a/tests/ref/bugs/newline-mode.png b/tests/ref/bugs/newline-mode.png Binary files differdeleted file mode 100644 index d4b6c6d8..00000000 --- a/tests/ref/bugs/newline-mode.png +++ /dev/null diff --git a/tests/ref/bugs/pagebreak-bibliography.png b/tests/ref/bugs/pagebreak-bibliography.png Binary files differdeleted file mode 100644 index 43de1574..00000000 --- a/tests/ref/bugs/pagebreak-bibliography.png +++ /dev/null diff --git a/tests/ref/bugs/pagebreak-numbering.png b/tests/ref/bugs/pagebreak-numbering.png Binary files differdeleted file mode 100644 index 96f047a8..00000000 --- a/tests/ref/bugs/pagebreak-numbering.png +++ /dev/null diff --git a/tests/ref/bugs/pagebreak-set-style.png b/tests/ref/bugs/pagebreak-set-style.png Binary files differdeleted file mode 100644 index f81b8c2f..00000000 --- a/tests/ref/bugs/pagebreak-set-style.png +++ /dev/null diff --git a/tests/ref/bugs/place-base.png b/tests/ref/bugs/place-base.png Binary files differdeleted file mode 100644 index 4442b173..00000000 --- a/tests/ref/bugs/place-base.png +++ /dev/null diff --git a/tests/ref/bugs/place-nested.png b/tests/ref/bugs/place-nested.png Binary files differdeleted file mode 100644 index b59dc5d3..00000000 --- a/tests/ref/bugs/place-nested.png +++ /dev/null diff --git a/tests/ref/bugs/place-pagebreak.png b/tests/ref/bugs/place-pagebreak.png Binary files differdeleted file mode 100644 index 2aa3d6b0..00000000 --- a/tests/ref/bugs/place-pagebreak.png +++ /dev/null diff --git a/tests/ref/bugs/place-spacing.png b/tests/ref/bugs/place-spacing.png Binary files differdeleted file mode 100644 index d14ce6ec..00000000 --- a/tests/ref/bugs/place-spacing.png +++ /dev/null diff --git a/tests/ref/bugs/raw-color-overwrite.png b/tests/ref/bugs/raw-color-overwrite.png Binary files differdeleted file mode 100644 index b01d86a4..00000000 --- a/tests/ref/bugs/raw-color-overwrite.png +++ /dev/null diff --git a/tests/ref/bugs/smartquotes-in-outline.png b/tests/ref/bugs/smartquotes-in-outline.png Binary files differdeleted file mode 100644 index 8a2cbc6a..00000000 --- a/tests/ref/bugs/smartquotes-in-outline.png +++ /dev/null diff --git a/tests/ref/bugs/smartquotes-on-newline.png b/tests/ref/bugs/smartquotes-on-newline.png Binary files differdeleted file mode 100644 index fdf4623a..00000000 --- a/tests/ref/bugs/smartquotes-on-newline.png +++ /dev/null diff --git a/tests/ref/bugs/spacing-behaviour.png b/tests/ref/bugs/spacing-behaviour.png Binary files differdeleted file mode 100644 index 08fcfa73..00000000 --- a/tests/ref/bugs/spacing-behaviour.png +++ /dev/null diff --git a/tests/ref/bugs/square-base.png b/tests/ref/bugs/square-base.png Binary files differdeleted file mode 100644 index 290ee54e..00000000 --- a/tests/ref/bugs/square-base.png +++ /dev/null diff --git a/tests/ref/bugs/table-lines.png b/tests/ref/bugs/table-lines.png Binary files differdeleted file mode 100644 index 600391cb..00000000 --- a/tests/ref/bugs/table-lines.png +++ /dev/null diff --git a/tests/ref/bugs/table-row-missing.png b/tests/ref/bugs/table-row-missing.png Binary files differdeleted file mode 100644 index 90c46d32..00000000 --- a/tests/ref/bugs/table-row-missing.png +++ /dev/null diff --git a/tests/ref/call-basic.png b/tests/ref/call-basic.png Binary files differnew file mode 100644 index 00000000..9016e9e8 --- /dev/null +++ b/tests/ref/call-basic.png diff --git a/tests/ref/circle-auto-sizing.png b/tests/ref/circle-auto-sizing.png Binary files differnew file mode 100644 index 00000000..377dbe1d --- /dev/null +++ b/tests/ref/circle-auto-sizing.png diff --git a/tests/ref/circle-directly-in-rect.png b/tests/ref/circle-directly-in-rect.png Binary files differnew file mode 100644 index 00000000..cb74496d --- /dev/null +++ b/tests/ref/circle-directly-in-rect.png diff --git a/tests/ref/circle-relative-sizing.png b/tests/ref/circle-relative-sizing.png Binary files differnew file mode 100644 index 00000000..efff34cf --- /dev/null +++ b/tests/ref/circle-relative-sizing.png diff --git a/tests/ref/circle-sizing-options.png b/tests/ref/circle-sizing-options.png Binary files differnew file mode 100644 index 00000000..778a8249 --- /dev/null +++ b/tests/ref/circle-sizing-options.png diff --git a/tests/ref/circle.png b/tests/ref/circle.png Binary files differnew file mode 100644 index 00000000..8a86e194 --- /dev/null +++ b/tests/ref/circle.png diff --git a/tests/ref/cite-footnote.png b/tests/ref/cite-footnote.png Binary files differnew file mode 100644 index 00000000..5bc6433e --- /dev/null +++ b/tests/ref/cite-footnote.png diff --git a/tests/ref/cite-form.png b/tests/ref/cite-form.png Binary files differnew file mode 100644 index 00000000..c35a3573 --- /dev/null +++ b/tests/ref/cite-form.png diff --git a/tests/ref/cite-group.png b/tests/ref/cite-group.png Binary files differnew file mode 100644 index 00000000..70feb4e1 --- /dev/null +++ b/tests/ref/cite-group.png diff --git a/tests/ref/cite-grouping-and-ordering.png b/tests/ref/cite-grouping-and-ordering.png Binary files differnew file mode 100644 index 00000000..6a70539d --- /dev/null +++ b/tests/ref/cite-grouping-and-ordering.png diff --git a/tests/ref/cjk-punctuation-adjustment-1.png b/tests/ref/cjk-punctuation-adjustment-1.png Binary files differnew file mode 100644 index 00000000..a68274cf --- /dev/null +++ b/tests/ref/cjk-punctuation-adjustment-1.png diff --git a/tests/ref/cjk-punctuation-adjustment-2.png b/tests/ref/cjk-punctuation-adjustment-2.png Binary files differnew file mode 100644 index 00000000..925c0f3c --- /dev/null +++ b/tests/ref/cjk-punctuation-adjustment-2.png diff --git a/tests/ref/cjk-punctuation-adjustment-3.png b/tests/ref/cjk-punctuation-adjustment-3.png Binary files differnew file mode 100644 index 00000000..e5eb70a9 --- /dev/null +++ b/tests/ref/cjk-punctuation-adjustment-3.png diff --git a/tests/ref/closure-capture-in-lvalue.png b/tests/ref/closure-capture-in-lvalue.png Binary files differnew file mode 100644 index 00000000..5f3ab035 --- /dev/null +++ b/tests/ref/closure-capture-in-lvalue.png diff --git a/tests/ref/closure-path-resolve-in-layout-phase.png b/tests/ref/closure-path-resolve-in-layout-phase.png Binary files differnew file mode 100644 index 00000000..e56e23a0 --- /dev/null +++ b/tests/ref/closure-path-resolve-in-layout-phase.png diff --git a/tests/ref/closure-without-params-non-atomic.png b/tests/ref/closure-without-params-non-atomic.png Binary files differnew file mode 100644 index 00000000..7d01ea3c --- /dev/null +++ b/tests/ref/closure-without-params-non-atomic.png diff --git a/tests/ref/code-block-basic-syntax.png b/tests/ref/code-block-basic-syntax.png Binary files differnew file mode 100644 index 00000000..7b2e6045 --- /dev/null +++ b/tests/ref/code-block-basic-syntax.png diff --git a/tests/ref/color-cmyk-ops.png b/tests/ref/color-cmyk-ops.png Binary files differnew file mode 100644 index 00000000..4f799efa --- /dev/null +++ b/tests/ref/color-cmyk-ops.png diff --git a/tests/ref/color-luma.png b/tests/ref/color-luma.png Binary files differnew file mode 100644 index 00000000..7bacc744 --- /dev/null +++ b/tests/ref/color-luma.png diff --git a/tests/ref/color-outside-srgb-gamut.png b/tests/ref/color-outside-srgb-gamut.png Binary files differnew file mode 100644 index 00000000..3a2806c5 --- /dev/null +++ b/tests/ref/color-outside-srgb-gamut.png diff --git a/tests/ref/color-rotate-hue.png b/tests/ref/color-rotate-hue.png Binary files differnew file mode 100644 index 00000000..a2139714 --- /dev/null +++ b/tests/ref/color-rotate-hue.png diff --git a/tests/ref/color-saturation.png b/tests/ref/color-saturation.png Binary files differnew file mode 100644 index 00000000..ccac4828 --- /dev/null +++ b/tests/ref/color-saturation.png diff --git a/tests/ref/color-spaces.png b/tests/ref/color-spaces.png Binary files differnew file mode 100644 index 00000000..ade861cc --- /dev/null +++ b/tests/ref/color-spaces.png diff --git a/tests/ref/columns-colbreak-after-place.png b/tests/ref/columns-colbreak-after-place.png Binary files differnew file mode 100644 index 00000000..f6a8a63d --- /dev/null +++ b/tests/ref/columns-colbreak-after-place.png diff --git a/tests/ref/columns-empty-second-column.png b/tests/ref/columns-empty-second-column.png Binary files differnew file mode 100644 index 00000000..a00d5fb2 --- /dev/null +++ b/tests/ref/columns-empty-second-column.png diff --git a/tests/ref/columns-in-auto-sized-rect.png b/tests/ref/columns-in-auto-sized-rect.png Binary files differnew file mode 100644 index 00000000..00088b7e --- /dev/null +++ b/tests/ref/columns-in-auto-sized-rect.png diff --git a/tests/ref/columns-in-fixed-size-rect.png b/tests/ref/columns-in-fixed-size-rect.png Binary files differnew file mode 100644 index 00000000..28cb97cb --- /dev/null +++ b/tests/ref/columns-in-fixed-size-rect.png diff --git a/tests/ref/columns-more-with-gutter.png b/tests/ref/columns-more-with-gutter.png Binary files differnew file mode 100644 index 00000000..e89c6a0b --- /dev/null +++ b/tests/ref/columns-more-with-gutter.png diff --git a/tests/ref/columns-one.png b/tests/ref/columns-one.png Binary files differnew file mode 100644 index 00000000..02abf659 --- /dev/null +++ b/tests/ref/columns-one.png diff --git a/tests/ref/columns-page-height-auto.png b/tests/ref/columns-page-height-auto.png Binary files differnew file mode 100644 index 00000000..9b3f1f85 --- /dev/null +++ b/tests/ref/columns-page-height-auto.png diff --git a/tests/ref/columns-page-width-auto.png b/tests/ref/columns-page-width-auto.png Binary files differnew file mode 100644 index 00000000..04d88bc1 --- /dev/null +++ b/tests/ref/columns-page-width-auto.png diff --git a/tests/ref/columns-rtl.png b/tests/ref/columns-rtl.png Binary files differnew file mode 100644 index 00000000..7efa57f5 --- /dev/null +++ b/tests/ref/columns-rtl.png diff --git a/tests/ref/columns-set-page-colbreak-pagebreak.png b/tests/ref/columns-set-page-colbreak-pagebreak.png Binary files differnew file mode 100644 index 00000000..48d2fd7b --- /dev/null +++ b/tests/ref/columns-set-page-colbreak-pagebreak.png diff --git a/tests/ref/columns-set-page.png b/tests/ref/columns-set-page.png Binary files differnew file mode 100644 index 00000000..42b5bea7 --- /dev/null +++ b/tests/ref/columns-set-page.png diff --git a/tests/ref/coma.png b/tests/ref/coma.png Binary files differindex fc0f6ba1..96f9e4d9 100644 --- a/tests/ref/coma.png +++ b/tests/ref/coma.png diff --git a/tests/ref/comment-end-of-line.png b/tests/ref/comment-end-of-line.png Binary files differnew file mode 100644 index 00000000..94da23cb --- /dev/null +++ b/tests/ref/comment-end-of-line.png diff --git a/tests/ref/comments.png b/tests/ref/comments.png Binary files differnew file mode 100644 index 00000000..892ff5e4 --- /dev/null +++ b/tests/ref/comments.png diff --git a/tests/ref/compiler/array.png b/tests/ref/compiler/array.png Binary files differdeleted file mode 100644 index 9b6bf8b3..00000000 --- a/tests/ref/compiler/array.png +++ /dev/null diff --git a/tests/ref/compiler/block.png b/tests/ref/compiler/block.png Binary files differdeleted file mode 100644 index 21a38de2..00000000 --- a/tests/ref/compiler/block.png +++ /dev/null diff --git a/tests/ref/compiler/break-continue.png b/tests/ref/compiler/break-continue.png Binary files differdeleted file mode 100644 index 9751d395..00000000 --- a/tests/ref/compiler/break-continue.png +++ /dev/null diff --git a/tests/ref/compiler/call.png b/tests/ref/compiler/call.png Binary files differdeleted file mode 100644 index 2c5d1e78..00000000 --- a/tests/ref/compiler/call.png +++ /dev/null diff --git a/tests/ref/compiler/closure.png b/tests/ref/compiler/closure.png Binary files differdeleted file mode 100644 index 07c171c5..00000000 --- a/tests/ref/compiler/closure.png +++ /dev/null diff --git a/tests/ref/compiler/color.png b/tests/ref/compiler/color.png Binary files differdeleted file mode 100644 index 2b416f64..00000000 --- a/tests/ref/compiler/color.png +++ /dev/null diff --git a/tests/ref/compiler/comment.png b/tests/ref/compiler/comment.png Binary files differdeleted file mode 100644 index 608df6ea..00000000 --- a/tests/ref/compiler/comment.png +++ /dev/null diff --git a/tests/ref/compiler/construct.png b/tests/ref/compiler/construct.png Binary files differdeleted file mode 100644 index f1acf665..00000000 --- a/tests/ref/compiler/construct.png +++ /dev/null diff --git a/tests/ref/compiler/content-field.png b/tests/ref/compiler/content-field.png Binary files differdeleted file mode 100644 index 3095ba8c..00000000 --- a/tests/ref/compiler/content-field.png +++ /dev/null diff --git a/tests/ref/compiler/dict.png b/tests/ref/compiler/dict.png Binary files differdeleted file mode 100644 index c97b2dbf..00000000 --- a/tests/ref/compiler/dict.png +++ /dev/null diff --git a/tests/ref/compiler/for.png b/tests/ref/compiler/for.png Binary files differdeleted file mode 100644 index 5608248f..00000000 --- a/tests/ref/compiler/for.png +++ /dev/null diff --git a/tests/ref/compiler/highlight.png b/tests/ref/compiler/highlight.png Binary files differdeleted file mode 100644 index ccbbc056..00000000 --- a/tests/ref/compiler/highlight.png +++ /dev/null diff --git a/tests/ref/compiler/if.png b/tests/ref/compiler/if.png Binary files differdeleted file mode 100644 index bd3adc88..00000000 --- a/tests/ref/compiler/if.png +++ /dev/null diff --git a/tests/ref/compiler/import.png b/tests/ref/compiler/import.png Binary files differdeleted file mode 100644 index 5c6132d2..00000000 --- a/tests/ref/compiler/import.png +++ /dev/null diff --git a/tests/ref/compiler/include.png b/tests/ref/compiler/include.png Binary files differdeleted file mode 100644 index 7fdb0310..00000000 --- a/tests/ref/compiler/include.png +++ /dev/null diff --git a/tests/ref/compiler/label.png b/tests/ref/compiler/label.png Binary files differdeleted file mode 100644 index 21764f97..00000000 --- a/tests/ref/compiler/label.png +++ /dev/null diff --git a/tests/ref/compiler/let.png b/tests/ref/compiler/let.png Binary files differdeleted file mode 100644 index 4423fe0a..00000000 --- a/tests/ref/compiler/let.png +++ /dev/null diff --git a/tests/ref/compiler/ops.png b/tests/ref/compiler/ops.png Binary files differdeleted file mode 100644 index 51fb9d1a..00000000 --- a/tests/ref/compiler/ops.png +++ /dev/null diff --git a/tests/ref/compiler/repr-color-gradient.png b/tests/ref/compiler/repr-color-gradient.png Binary files differdeleted file mode 100644 index 11bde774..00000000 --- a/tests/ref/compiler/repr-color-gradient.png +++ /dev/null diff --git a/tests/ref/compiler/repr.png b/tests/ref/compiler/repr.png Binary files differdeleted file mode 100644 index c90cc3cd..00000000 --- a/tests/ref/compiler/repr.png +++ /dev/null diff --git a/tests/ref/compiler/return.png b/tests/ref/compiler/return.png Binary files differdeleted file mode 100644 index e8fa3ab2..00000000 --- a/tests/ref/compiler/return.png +++ /dev/null diff --git a/tests/ref/compiler/select-where-styles.png b/tests/ref/compiler/select-where-styles.png Binary files differdeleted file mode 100644 index ffdc4bab..00000000 --- a/tests/ref/compiler/select-where-styles.png +++ /dev/null diff --git a/tests/ref/compiler/selector-logical.png b/tests/ref/compiler/selector-logical.png Binary files differdeleted file mode 100644 index eafa93c8..00000000 --- a/tests/ref/compiler/selector-logical.png +++ /dev/null diff --git a/tests/ref/compiler/set.png b/tests/ref/compiler/set.png Binary files differdeleted file mode 100644 index 26409396..00000000 --- a/tests/ref/compiler/set.png +++ /dev/null diff --git a/tests/ref/compiler/shorthand.png b/tests/ref/compiler/shorthand.png Binary files differdeleted file mode 100644 index 4507177b..00000000 --- a/tests/ref/compiler/shorthand.png +++ /dev/null diff --git a/tests/ref/compiler/show-bare.png b/tests/ref/compiler/show-bare.png Binary files differdeleted file mode 100644 index c6a1e101..00000000 --- a/tests/ref/compiler/show-bare.png +++ /dev/null diff --git a/tests/ref/compiler/show-node.png b/tests/ref/compiler/show-node.png Binary files differdeleted file mode 100644 index 396e5429..00000000 --- a/tests/ref/compiler/show-node.png +++ /dev/null diff --git a/tests/ref/compiler/show-recursive.png b/tests/ref/compiler/show-recursive.png Binary files differdeleted file mode 100644 index a5a153c0..00000000 --- a/tests/ref/compiler/show-recursive.png +++ /dev/null diff --git a/tests/ref/compiler/show-selector-logical.png b/tests/ref/compiler/show-selector-logical.png Binary files differdeleted file mode 100644 index a7a80053..00000000 --- a/tests/ref/compiler/show-selector-logical.png +++ /dev/null diff --git a/tests/ref/compiler/show-selector.png b/tests/ref/compiler/show-selector.png Binary files differdeleted file mode 100644 index 52e99c9a..00000000 --- a/tests/ref/compiler/show-selector.png +++ /dev/null diff --git a/tests/ref/compiler/show-set-func.png b/tests/ref/compiler/show-set-func.png Binary files differdeleted file mode 100644 index c5ff2489..00000000 --- a/tests/ref/compiler/show-set-func.png +++ /dev/null diff --git a/tests/ref/compiler/show-set-text.png b/tests/ref/compiler/show-set-text.png Binary files differdeleted file mode 100644 index 27803e8a..00000000 --- a/tests/ref/compiler/show-set-text.png +++ /dev/null diff --git a/tests/ref/compiler/show-set.png b/tests/ref/compiler/show-set.png Binary files differdeleted file mode 100644 index e87fc600..00000000 --- a/tests/ref/compiler/show-set.png +++ /dev/null diff --git a/tests/ref/compiler/show-text.png b/tests/ref/compiler/show-text.png Binary files differdeleted file mode 100644 index 2026cc35..00000000 --- a/tests/ref/compiler/show-text.png +++ /dev/null diff --git a/tests/ref/compiler/while.png b/tests/ref/compiler/while.png Binary files differdeleted file mode 100644 index d0f86473..00000000 --- a/tests/ref/compiler/while.png +++ /dev/null diff --git a/tests/ref/compute/construct.png b/tests/ref/compute/construct.png Binary files differdeleted file mode 100644 index e1717473..00000000 --- a/tests/ref/compute/construct.png +++ /dev/null diff --git a/tests/ref/compute/data.png b/tests/ref/compute/data.png Binary files differdeleted file mode 100644 index 2dab6875..00000000 --- a/tests/ref/compute/data.png +++ /dev/null diff --git a/tests/ref/compute/eval-path.png b/tests/ref/compute/eval-path.png Binary files differdeleted file mode 100644 index c59dd2aa..00000000 --- a/tests/ref/compute/eval-path.png +++ /dev/null diff --git a/tests/ref/compute/foundations.png b/tests/ref/compute/foundations.png Binary files differdeleted file mode 100644 index 5d6ba744..00000000 --- a/tests/ref/compute/foundations.png +++ /dev/null diff --git a/tests/ref/content-field-materialized-heading.png b/tests/ref/content-field-materialized-heading.png Binary files differnew file mode 100644 index 00000000..72201627 --- /dev/null +++ b/tests/ref/content-field-materialized-heading.png diff --git a/tests/ref/content-field-materialized-query.png b/tests/ref/content-field-materialized-query.png Binary files differnew file mode 100644 index 00000000..2d2a1480 --- /dev/null +++ b/tests/ref/content-field-materialized-query.png diff --git a/tests/ref/content-field-materialized-table.png b/tests/ref/content-field-materialized-table.png Binary files differnew file mode 100644 index 00000000..09efe753 --- /dev/null +++ b/tests/ref/content-field-materialized-table.png diff --git a/tests/ref/content-fields-complex.png b/tests/ref/content-fields-complex.png Binary files differnew file mode 100644 index 00000000..624a8b33 --- /dev/null +++ b/tests/ref/content-fields-complex.png diff --git a/tests/ref/content-label-field-access.png b/tests/ref/content-label-field-access.png Binary files differnew file mode 100644 index 00000000..bdb7c0f2 --- /dev/null +++ b/tests/ref/content-label-field-access.png diff --git a/tests/ref/content-label-fields-method.png b/tests/ref/content-label-fields-method.png Binary files differnew file mode 100644 index 00000000..bdb7c0f2 --- /dev/null +++ b/tests/ref/content-label-fields-method.png diff --git a/tests/ref/content-label-has-method.png b/tests/ref/content-label-has-method.png Binary files differnew file mode 100644 index 00000000..bdb7c0f2 --- /dev/null +++ b/tests/ref/content-label-has-method.png diff --git a/tests/ref/context-compatibility-locate.png b/tests/ref/context-compatibility-locate.png Binary files differnew file mode 100644 index 00000000..4c8944ab --- /dev/null +++ b/tests/ref/context-compatibility-locate.png diff --git a/tests/ref/context-compatibility-styling.png b/tests/ref/context-compatibility-styling.png Binary files differnew file mode 100644 index 00000000..aee16c3a --- /dev/null +++ b/tests/ref/context-compatibility-styling.png diff --git a/tests/ref/counter-basic-1.png b/tests/ref/counter-basic-1.png Binary files differnew file mode 100644 index 00000000..92282594 --- /dev/null +++ b/tests/ref/counter-basic-1.png diff --git a/tests/ref/counter-figure.png b/tests/ref/counter-figure.png Binary files differnew file mode 100644 index 00000000..5e4a4a5f --- /dev/null +++ b/tests/ref/counter-figure.png diff --git a/tests/ref/counter-heading.png b/tests/ref/counter-heading.png Binary files differnew file mode 100644 index 00000000..96dafd6a --- /dev/null +++ b/tests/ref/counter-heading.png diff --git a/tests/ref/counter-label.png b/tests/ref/counter-label.png Binary files differnew file mode 100644 index 00000000..6fea90df --- /dev/null +++ b/tests/ref/counter-label.png diff --git a/tests/ref/counter-page.png b/tests/ref/counter-page.png Binary files differnew file mode 100644 index 00000000..be1653eb --- /dev/null +++ b/tests/ref/counter-page.png diff --git a/tests/ref/csv.png b/tests/ref/csv.png Binary files differnew file mode 100644 index 00000000..fd0c9a1c --- /dev/null +++ b/tests/ref/csv.png diff --git a/tests/ref/destructuring-during-loop-continue.png b/tests/ref/destructuring-during-loop-continue.png Binary files differnew file mode 100644 index 00000000..9ea8e3c1 --- /dev/null +++ b/tests/ref/destructuring-during-loop-continue.png diff --git a/tests/ref/dict-basic-methods.png b/tests/ref/dict-basic-methods.png Binary files differnew file mode 100644 index 00000000..20410cc3 --- /dev/null +++ b/tests/ref/dict-basic-methods.png diff --git a/tests/ref/dict-basic-syntax.png b/tests/ref/dict-basic-syntax.png Binary files differnew file mode 100644 index 00000000..02effef6 --- /dev/null +++ b/tests/ref/dict-basic-syntax.png diff --git a/tests/ref/dict-from-module.png b/tests/ref/dict-from-module.png Binary files differnew file mode 100644 index 00000000..7fd6eec3 --- /dev/null +++ b/tests/ref/dict-from-module.png diff --git a/tests/ref/dict-remove-order.png b/tests/ref/dict-remove-order.png Binary files differnew file mode 100644 index 00000000..20410cc3 --- /dev/null +++ b/tests/ref/dict-remove-order.png diff --git a/tests/ref/document-set-title.png b/tests/ref/document-set-title.png Binary files differnew file mode 100644 index 00000000..74bcfe19 --- /dev/null +++ b/tests/ref/document-set-title.png diff --git a/tests/ref/ellipse-auto-sizing.png b/tests/ref/ellipse-auto-sizing.png Binary files differnew file mode 100644 index 00000000..ed201521 --- /dev/null +++ b/tests/ref/ellipse-auto-sizing.png diff --git a/tests/ref/ellipse.png b/tests/ref/ellipse.png Binary files differnew file mode 100644 index 00000000..0f4e92ca --- /dev/null +++ b/tests/ref/ellipse.png diff --git a/tests/ref/emph-and-strong-call-in-word.png b/tests/ref/emph-and-strong-call-in-word.png Binary files differnew file mode 100644 index 00000000..4720f994 --- /dev/null +++ b/tests/ref/emph-and-strong-call-in-word.png diff --git a/tests/ref/emph-double-underscore-empty-hint.png b/tests/ref/emph-double-underscore-empty-hint.png Binary files differnew file mode 100644 index 00000000..a940dfb6 --- /dev/null +++ b/tests/ref/emph-double-underscore-empty-hint.png diff --git a/tests/ref/emph-syntax.png b/tests/ref/emph-syntax.png Binary files differnew file mode 100644 index 00000000..66f117a8 --- /dev/null +++ b/tests/ref/emph-syntax.png diff --git a/tests/ref/empty.png b/tests/ref/empty.png Binary files differdeleted file mode 100644 index db3a6695..00000000 --- a/tests/ref/empty.png +++ /dev/null diff --git a/tests/ref/enum-built-in-loop.png b/tests/ref/enum-built-in-loop.png Binary files differnew file mode 100644 index 00000000..298518da --- /dev/null +++ b/tests/ref/enum-built-in-loop.png diff --git a/tests/ref/enum-function-call.png b/tests/ref/enum-function-call.png Binary files differnew file mode 100644 index 00000000..a451f27c --- /dev/null +++ b/tests/ref/enum-function-call.png diff --git a/tests/ref/enum-number-align-2d.png b/tests/ref/enum-number-align-2d.png Binary files differnew file mode 100644 index 00000000..e205844f --- /dev/null +++ b/tests/ref/enum-number-align-2d.png diff --git a/tests/ref/enum-number-align-default.png b/tests/ref/enum-number-align-default.png Binary files differnew file mode 100644 index 00000000..c47f9001 --- /dev/null +++ b/tests/ref/enum-number-align-default.png diff --git a/tests/ref/enum-number-align-specified.png b/tests/ref/enum-number-align-specified.png Binary files differnew file mode 100644 index 00000000..b2f2d619 --- /dev/null +++ b/tests/ref/enum-number-align-specified.png diff --git a/tests/ref/enum-number-align-unaffected.png b/tests/ref/enum-number-align-unaffected.png Binary files differnew file mode 100644 index 00000000..3abcaaab --- /dev/null +++ b/tests/ref/enum-number-align-unaffected.png diff --git a/tests/ref/enum-number-align-unfolded.png b/tests/ref/enum-number-align-unfolded.png Binary files differnew file mode 100644 index 00000000..8c4f2943 --- /dev/null +++ b/tests/ref/enum-number-align-unfolded.png diff --git a/tests/ref/enum-number-override-nested.png b/tests/ref/enum-number-override-nested.png Binary files differnew file mode 100644 index 00000000..22bb7611 --- /dev/null +++ b/tests/ref/enum-number-override-nested.png diff --git a/tests/ref/enum-number-override.png b/tests/ref/enum-number-override.png Binary files differnew file mode 100644 index 00000000..65c0f9d8 --- /dev/null +++ b/tests/ref/enum-number-override.png diff --git a/tests/ref/enum-numbering-closure-nested-complex.png b/tests/ref/enum-numbering-closure-nested-complex.png Binary files differnew file mode 100644 index 00000000..a756f37c --- /dev/null +++ b/tests/ref/enum-numbering-closure-nested-complex.png diff --git a/tests/ref/enum-numbering-closure-nested.png b/tests/ref/enum-numbering-closure-nested.png Binary files differnew file mode 100644 index 00000000..25a5c42d --- /dev/null +++ b/tests/ref/enum-numbering-closure-nested.png diff --git a/tests/ref/enum-numbering-closure.png b/tests/ref/enum-numbering-closure.png Binary files differnew file mode 100644 index 00000000..bf86f554 --- /dev/null +++ b/tests/ref/enum-numbering-closure.png diff --git a/tests/ref/enum-numbering-full.png b/tests/ref/enum-numbering-full.png Binary files differnew file mode 100644 index 00000000..46449e57 --- /dev/null +++ b/tests/ref/enum-numbering-full.png diff --git a/tests/ref/enum-numbering-pattern.png b/tests/ref/enum-numbering-pattern.png Binary files differnew file mode 100644 index 00000000..4ecb9e4a --- /dev/null +++ b/tests/ref/enum-numbering-pattern.png diff --git a/tests/ref/enum-syntax-at-start.png b/tests/ref/enum-syntax-at-start.png Binary files differnew file mode 100644 index 00000000..ce9f3967 --- /dev/null +++ b/tests/ref/enum-syntax-at-start.png diff --git a/tests/ref/enum-syntax-edge-cases.png b/tests/ref/enum-syntax-edge-cases.png Binary files differnew file mode 100644 index 00000000..496dc8e3 --- /dev/null +++ b/tests/ref/enum-syntax-edge-cases.png diff --git a/tests/ref/escape.png b/tests/ref/escape.png Binary files differnew file mode 100644 index 00000000..0b49606c --- /dev/null +++ b/tests/ref/escape.png diff --git a/tests/ref/eval-in-show-rule.png b/tests/ref/eval-in-show-rule.png Binary files differnew file mode 100644 index 00000000..91a03868 --- /dev/null +++ b/tests/ref/eval-in-show-rule.png diff --git a/tests/ref/eval-mode.png b/tests/ref/eval-mode.png Binary files differnew file mode 100644 index 00000000..94357ff4 --- /dev/null +++ b/tests/ref/eval-mode.png diff --git a/tests/ref/eval-path-resolve-in-show-rule.png b/tests/ref/eval-path-resolve-in-show-rule.png Binary files differnew file mode 100644 index 00000000..cf5c183a --- /dev/null +++ b/tests/ref/eval-path-resolve-in-show-rule.png diff --git a/tests/ref/eval-path-resolve.png b/tests/ref/eval-path-resolve.png Binary files differnew file mode 100644 index 00000000..cf5c183a --- /dev/null +++ b/tests/ref/eval-path-resolve.png diff --git a/tests/ref/field-function.png b/tests/ref/field-function.png Binary files differnew file mode 100644 index 00000000..261fb395 --- /dev/null +++ b/tests/ref/field-function.png diff --git a/tests/ref/figure-and-caption-show.png b/tests/ref/figure-and-caption-show.png Binary files differnew file mode 100644 index 00000000..daf8f2b6 --- /dev/null +++ b/tests/ref/figure-and-caption-show.png diff --git a/tests/ref/figure-basic.png b/tests/ref/figure-basic.png Binary files differnew file mode 100644 index 00000000..22a841db --- /dev/null +++ b/tests/ref/figure-basic.png diff --git a/tests/ref/figure-breakable.png b/tests/ref/figure-breakable.png Binary files differnew file mode 100644 index 00000000..40cb3ec5 --- /dev/null +++ b/tests/ref/figure-breakable.png diff --git a/tests/ref/figure-caption-separator.png b/tests/ref/figure-caption-separator.png Binary files differnew file mode 100644 index 00000000..e645f01f --- /dev/null +++ b/tests/ref/figure-caption-separator.png diff --git a/tests/ref/figure-caption-show.png b/tests/ref/figure-caption-show.png Binary files differnew file mode 100644 index 00000000..4ed6443a --- /dev/null +++ b/tests/ref/figure-caption-show.png diff --git a/tests/ref/figure-caption-where-selector.png b/tests/ref/figure-caption-where-selector.png Binary files differnew file mode 100644 index 00000000..08eb46f6 --- /dev/null +++ b/tests/ref/figure-caption-where-selector.png diff --git a/tests/ref/figure-localization-fr.png b/tests/ref/figure-localization-fr.png Binary files differnew file mode 100644 index 00000000..665b3552 --- /dev/null +++ b/tests/ref/figure-localization-fr.png diff --git a/tests/ref/figure-localization-gr.png b/tests/ref/figure-localization-gr.png Binary files differnew file mode 100644 index 00000000..46b52b05 --- /dev/null +++ b/tests/ref/figure-localization-gr.png diff --git a/tests/ref/figure-localization-ru.png b/tests/ref/figure-localization-ru.png Binary files differnew file mode 100644 index 00000000..102df597 --- /dev/null +++ b/tests/ref/figure-localization-ru.png diff --git a/tests/ref/figure-localization-zh.png b/tests/ref/figure-localization-zh.png Binary files differnew file mode 100644 index 00000000..f7625b1b --- /dev/null +++ b/tests/ref/figure-localization-zh.png diff --git a/tests/ref/figure-table.png b/tests/ref/figure-table.png Binary files differnew file mode 100644 index 00000000..9a09f659 --- /dev/null +++ b/tests/ref/figure-table.png diff --git a/tests/ref/figure-theorem.png b/tests/ref/figure-theorem.png Binary files differnew file mode 100644 index 00000000..10d6eeac --- /dev/null +++ b/tests/ref/figure-theorem.png diff --git a/tests/ref/float-display.png b/tests/ref/float-display.png Binary files differnew file mode 100644 index 00000000..6c33b372 --- /dev/null +++ b/tests/ref/float-display.png diff --git a/tests/ref/float-repr.png b/tests/ref/float-repr.png Binary files differnew file mode 100644 index 00000000..8b510969 --- /dev/null +++ b/tests/ref/float-repr.png diff --git a/tests/ref/flow-first-region-counter-update-and-placed.png b/tests/ref/flow-first-region-counter-update-and-placed.png Binary files differnew file mode 100644 index 00000000..21316719 --- /dev/null +++ b/tests/ref/flow-first-region-counter-update-and-placed.png diff --git a/tests/ref/flow-first-region-counter-update-placed-and-line.png b/tests/ref/flow-first-region-counter-update-placed-and-line.png Binary files differnew file mode 100644 index 00000000..95ca518e --- /dev/null +++ b/tests/ref/flow-first-region-counter-update-placed-and-line.png diff --git a/tests/ref/flow-first-region-counter-update.png b/tests/ref/flow-first-region-counter-update.png Binary files differnew file mode 100644 index 00000000..8e883335 --- /dev/null +++ b/tests/ref/flow-first-region-counter-update.png diff --git a/tests/ref/flow-first-region-no-item.png b/tests/ref/flow-first-region-no-item.png Binary files differnew file mode 100644 index 00000000..e888898c --- /dev/null +++ b/tests/ref/flow-first-region-no-item.png diff --git a/tests/ref/flow-first-region-placed.png b/tests/ref/flow-first-region-placed.png Binary files differnew file mode 100644 index 00000000..cae4aa32 --- /dev/null +++ b/tests/ref/flow-first-region-placed.png diff --git a/tests/ref/flow-first-region-zero-sized-item.png b/tests/ref/flow-first-region-zero-sized-item.png Binary files differnew file mode 100644 index 00000000..2e75fcfe --- /dev/null +++ b/tests/ref/flow-first-region-zero-sized-item.png diff --git a/tests/ref/flow-fr.png b/tests/ref/flow-fr.png Binary files differnew file mode 100644 index 00000000..b09a9604 --- /dev/null +++ b/tests/ref/flow-fr.png diff --git a/tests/ref/flow-heading-no-orphan.png b/tests/ref/flow-heading-no-orphan.png Binary files differnew file mode 100644 index 00000000..87789ea1 --- /dev/null +++ b/tests/ref/flow-heading-no-orphan.png diff --git a/tests/ref/flow-par-no-orphan-and-widow-lines.png b/tests/ref/flow-par-no-orphan-and-widow-lines.png Binary files differnew file mode 100644 index 00000000..cace5d44 --- /dev/null +++ b/tests/ref/flow-par-no-orphan-and-widow-lines.png diff --git a/tests/ref/fold-vec-order-meta.png b/tests/ref/fold-vec-order-meta.png Binary files differnew file mode 100644 index 00000000..36e3cd51 --- /dev/null +++ b/tests/ref/fold-vec-order-meta.png diff --git a/tests/ref/fold-vec-order-text-decos.png b/tests/ref/fold-vec-order-text-decos.png Binary files differnew file mode 100644 index 00000000..62c9e1af --- /dev/null +++ b/tests/ref/fold-vec-order-text-decos.png diff --git a/tests/ref/fold-vec-order-text-features.png b/tests/ref/fold-vec-order-text-features.png Binary files differnew file mode 100644 index 00000000..f2ff6f25 --- /dev/null +++ b/tests/ref/fold-vec-order-text-features.png diff --git a/tests/ref/footnote-basic.png b/tests/ref/footnote-basic.png Binary files differnew file mode 100644 index 00000000..3562438b --- /dev/null +++ b/tests/ref/footnote-basic.png diff --git a/tests/ref/footnote-break-across-pages.png b/tests/ref/footnote-break-across-pages.png Binary files differnew file mode 100644 index 00000000..8ec55418 --- /dev/null +++ b/tests/ref/footnote-break-across-pages.png diff --git a/tests/ref/footnote-duplicate.png b/tests/ref/footnote-duplicate.png Binary files differnew file mode 100644 index 00000000..7c83b8de --- /dev/null +++ b/tests/ref/footnote-duplicate.png diff --git a/tests/ref/footnote-entry.png b/tests/ref/footnote-entry.png Binary files differnew file mode 100644 index 00000000..e62315c4 --- /dev/null +++ b/tests/ref/footnote-entry.png diff --git a/tests/ref/footnote-in-caption.png b/tests/ref/footnote-in-caption.png Binary files differnew file mode 100644 index 00000000..8d548c59 --- /dev/null +++ b/tests/ref/footnote-in-caption.png diff --git a/tests/ref/footnote-in-columns.png b/tests/ref/footnote-in-columns.png Binary files differnew file mode 100644 index 00000000..e16b4ebc --- /dev/null +++ b/tests/ref/footnote-in-columns.png diff --git a/tests/ref/footnote-in-table.png b/tests/ref/footnote-in-table.png Binary files differnew file mode 100644 index 00000000..0fd0acc7 --- /dev/null +++ b/tests/ref/footnote-in-table.png diff --git a/tests/ref/footnote-invariant.png b/tests/ref/footnote-invariant.png Binary files differnew file mode 100644 index 00000000..c49c268d --- /dev/null +++ b/tests/ref/footnote-invariant.png diff --git a/tests/ref/footnote-nested-same-frame.png b/tests/ref/footnote-nested-same-frame.png Binary files differnew file mode 100644 index 00000000..b22276d5 --- /dev/null +++ b/tests/ref/footnote-nested-same-frame.png diff --git a/tests/ref/footnote-nested.png b/tests/ref/footnote-nested.png Binary files differnew file mode 100644 index 00000000..fecf2e8d --- /dev/null +++ b/tests/ref/footnote-nested.png diff --git a/tests/ref/footnote-ref-call.png b/tests/ref/footnote-ref-call.png Binary files differnew file mode 100644 index 00000000..3c795302 --- /dev/null +++ b/tests/ref/footnote-ref-call.png diff --git a/tests/ref/footnote-ref-forward.png b/tests/ref/footnote-ref-forward.png Binary files differnew file mode 100644 index 00000000..e67671be --- /dev/null +++ b/tests/ref/footnote-ref-forward.png diff --git a/tests/ref/footnote-ref-in-footnote.png b/tests/ref/footnote-ref-in-footnote.png Binary files differnew file mode 100644 index 00000000..4718a088 --- /dev/null +++ b/tests/ref/footnote-ref-in-footnote.png diff --git a/tests/ref/footnote-ref-multiple.png b/tests/ref/footnote-ref-multiple.png Binary files differnew file mode 100644 index 00000000..fc6f11cf --- /dev/null +++ b/tests/ref/footnote-ref-multiple.png diff --git a/tests/ref/footnote-ref.png b/tests/ref/footnote-ref.png Binary files differnew file mode 100644 index 00000000..517d997a --- /dev/null +++ b/tests/ref/footnote-ref.png diff --git a/tests/ref/footnote-space-collapsing.png b/tests/ref/footnote-space-collapsing.png Binary files differnew file mode 100644 index 00000000..d7d02704 --- /dev/null +++ b/tests/ref/footnote-space-collapsing.png diff --git a/tests/ref/footnote-styling.png b/tests/ref/footnote-styling.png Binary files differnew file mode 100644 index 00000000..fd7684af --- /dev/null +++ b/tests/ref/footnote-styling.png diff --git a/tests/ref/for-loop-basic.png b/tests/ref/for-loop-basic.png Binary files differnew file mode 100644 index 00000000..42d611ef --- /dev/null +++ b/tests/ref/for-loop-basic.png diff --git a/tests/ref/gradient-conic-angled.png b/tests/ref/gradient-conic-angled.png Binary files differnew file mode 100644 index 00000000..163366e6 --- /dev/null +++ b/tests/ref/gradient-conic-angled.png diff --git a/tests/ref/gradient-conic-center-shifted-1.png b/tests/ref/gradient-conic-center-shifted-1.png Binary files differnew file mode 100644 index 00000000..5964b124 --- /dev/null +++ b/tests/ref/gradient-conic-center-shifted-1.png diff --git a/tests/ref/gradient-conic-center-shifted-2.png b/tests/ref/gradient-conic-center-shifted-2.png Binary files differnew file mode 100644 index 00000000..53e5da98 --- /dev/null +++ b/tests/ref/gradient-conic-center-shifted-2.png diff --git a/tests/ref/gradient-conic-hsl.png b/tests/ref/gradient-conic-hsl.png Binary files differnew file mode 100644 index 00000000..321a3b07 --- /dev/null +++ b/tests/ref/gradient-conic-hsl.png diff --git a/tests/ref/gradient-conic-hsv.png b/tests/ref/gradient-conic-hsv.png Binary files differnew file mode 100644 index 00000000..648e1fb5 --- /dev/null +++ b/tests/ref/gradient-conic-hsv.png diff --git a/tests/ref/gradient-conic-oklab.png b/tests/ref/gradient-conic-oklab.png Binary files differnew file mode 100644 index 00000000..e567eacc --- /dev/null +++ b/tests/ref/gradient-conic-oklab.png diff --git a/tests/ref/gradient-conic-oklch.png b/tests/ref/gradient-conic-oklch.png Binary files differnew file mode 100644 index 00000000..f712defa --- /dev/null +++ b/tests/ref/gradient-conic-oklch.png diff --git a/tests/ref/gradient-conic-relative-parent.png b/tests/ref/gradient-conic-relative-parent.png Binary files differnew file mode 100644 index 00000000..1685ca44 --- /dev/null +++ b/tests/ref/gradient-conic-relative-parent.png diff --git a/tests/ref/gradient-conic-relative-self.png b/tests/ref/gradient-conic-relative-self.png Binary files differnew file mode 100644 index 00000000..108fe43a --- /dev/null +++ b/tests/ref/gradient-conic-relative-self.png diff --git a/tests/ref/gradient-conic-stroke.png b/tests/ref/gradient-conic-stroke.png Binary files differnew file mode 100644 index 00000000..ae631fd4 --- /dev/null +++ b/tests/ref/gradient-conic-stroke.png diff --git a/tests/ref/gradient-conic-text.png b/tests/ref/gradient-conic-text.png Binary files differnew file mode 100644 index 00000000..1abef3cb --- /dev/null +++ b/tests/ref/gradient-conic-text.png diff --git a/tests/ref/gradient-conic.png b/tests/ref/gradient-conic.png Binary files differnew file mode 100644 index 00000000..0f5f5bad --- /dev/null +++ b/tests/ref/gradient-conic.png diff --git a/tests/ref/gradient-fill-and-stroke.png b/tests/ref/gradient-fill-and-stroke.png Binary files differnew file mode 100644 index 00000000..78563517 --- /dev/null +++ b/tests/ref/gradient-fill-and-stroke.png diff --git a/tests/ref/gradient-linear-angled.png b/tests/ref/gradient-linear-angled.png Binary files differnew file mode 100644 index 00000000..b195b128 --- /dev/null +++ b/tests/ref/gradient-linear-angled.png diff --git a/tests/ref/gradient-linear-hsl.png b/tests/ref/gradient-linear-hsl.png Binary files differnew file mode 100644 index 00000000..7bfe958b --- /dev/null +++ b/tests/ref/gradient-linear-hsl.png diff --git a/tests/ref/gradient-linear-hsv.png b/tests/ref/gradient-linear-hsv.png Binary files differnew file mode 100644 index 00000000..56b446f2 --- /dev/null +++ b/tests/ref/gradient-linear-hsv.png diff --git a/tests/ref/gradient-linear-line.png b/tests/ref/gradient-linear-line.png Binary files differnew file mode 100644 index 00000000..d32aba89 --- /dev/null +++ b/tests/ref/gradient-linear-line.png diff --git a/tests/ref/gradient-linear-oklab.png b/tests/ref/gradient-linear-oklab.png Binary files differnew file mode 100644 index 00000000..6f963c77 --- /dev/null +++ b/tests/ref/gradient-linear-oklab.png diff --git a/tests/ref/gradient-linear-oklch.png b/tests/ref/gradient-linear-oklch.png Binary files differnew file mode 100644 index 00000000..394d0935 --- /dev/null +++ b/tests/ref/gradient-linear-oklch.png diff --git a/tests/ref/gradient-linear-relative-parent.png b/tests/ref/gradient-linear-relative-parent.png Binary files differnew file mode 100644 index 00000000..2ad1286e --- /dev/null +++ b/tests/ref/gradient-linear-relative-parent.png diff --git a/tests/ref/gradient-linear-relative-self.png b/tests/ref/gradient-linear-relative-self.png Binary files differnew file mode 100644 index 00000000..d573a892 --- /dev/null +++ b/tests/ref/gradient-linear-relative-self.png diff --git a/tests/ref/gradient-linear-repeat-and-mirror-1.png b/tests/ref/gradient-linear-repeat-and-mirror-1.png Binary files differnew file mode 100644 index 00000000..9640d5e2 --- /dev/null +++ b/tests/ref/gradient-linear-repeat-and-mirror-1.png diff --git a/tests/ref/gradient-linear-repeat-and-mirror-2.png b/tests/ref/gradient-linear-repeat-and-mirror-2.png Binary files differnew file mode 100644 index 00000000..98cf2543 --- /dev/null +++ b/tests/ref/gradient-linear-repeat-and-mirror-2.png diff --git a/tests/ref/gradient-linear-repeat-and-mirror-3.png b/tests/ref/gradient-linear-repeat-and-mirror-3.png Binary files differnew file mode 100644 index 00000000..641e54c9 --- /dev/null +++ b/tests/ref/gradient-linear-repeat-and-mirror-3.png diff --git a/tests/ref/gradient-linear-sharp-and-repeat.png b/tests/ref/gradient-linear-sharp-and-repeat.png Binary files differnew file mode 100644 index 00000000..e46af7a0 --- /dev/null +++ b/tests/ref/gradient-linear-sharp-and-repeat.png diff --git a/tests/ref/gradient-linear-sharp-and-smooth.png b/tests/ref/gradient-linear-sharp-and-smooth.png Binary files differnew file mode 100644 index 00000000..5bd74d24 --- /dev/null +++ b/tests/ref/gradient-linear-sharp-and-smooth.png diff --git a/tests/ref/gradient-linear-sharp-repeat-and-mirror.png b/tests/ref/gradient-linear-sharp-repeat-and-mirror.png Binary files differnew file mode 100644 index 00000000..5b4b9817 --- /dev/null +++ b/tests/ref/gradient-linear-sharp-repeat-and-mirror.png diff --git a/tests/ref/gradient-linear-sharp.png b/tests/ref/gradient-linear-sharp.png Binary files differnew file mode 100644 index 00000000..4d63884f --- /dev/null +++ b/tests/ref/gradient-linear-sharp.png diff --git a/tests/ref/gradient-linear-stroke.png b/tests/ref/gradient-linear-stroke.png Binary files differnew file mode 100644 index 00000000..490ffec2 --- /dev/null +++ b/tests/ref/gradient-linear-stroke.png diff --git a/tests/ref/gradient-math-cancel.png b/tests/ref/gradient-math-cancel.png Binary files differnew file mode 100644 index 00000000..0769d6d3 --- /dev/null +++ b/tests/ref/gradient-math-cancel.png diff --git a/tests/ref/gradient-math-conic.png b/tests/ref/gradient-math-conic.png Binary files differnew file mode 100644 index 00000000..88ff7a85 --- /dev/null +++ b/tests/ref/gradient-math-conic.png diff --git a/tests/ref/gradient-math-dir.png b/tests/ref/gradient-math-dir.png Binary files differnew file mode 100644 index 00000000..5ed19182 --- /dev/null +++ b/tests/ref/gradient-math-dir.png diff --git a/tests/ref/gradient-math-frac.png b/tests/ref/gradient-math-frac.png Binary files differnew file mode 100644 index 00000000..1316dc47 --- /dev/null +++ b/tests/ref/gradient-math-frac.png diff --git a/tests/ref/gradient-math-mat.png b/tests/ref/gradient-math-mat.png Binary files differnew file mode 100644 index 00000000..aa3332b9 --- /dev/null +++ b/tests/ref/gradient-math-mat.png diff --git a/tests/ref/gradient-math-misc.png b/tests/ref/gradient-math-misc.png Binary files differnew file mode 100644 index 00000000..b8fbdd74 --- /dev/null +++ b/tests/ref/gradient-math-misc.png diff --git a/tests/ref/gradient-math-radial.png b/tests/ref/gradient-math-radial.png Binary files differnew file mode 100644 index 00000000..c9b966b2 --- /dev/null +++ b/tests/ref/gradient-math-radial.png diff --git a/tests/ref/gradient-math-root.png b/tests/ref/gradient-math-root.png Binary files differnew file mode 100644 index 00000000..4c2e4272 --- /dev/null +++ b/tests/ref/gradient-math-root.png diff --git a/tests/ref/gradient-math-underover.png b/tests/ref/gradient-math-underover.png Binary files differnew file mode 100644 index 00000000..89098051 --- /dev/null +++ b/tests/ref/gradient-math-underover.png diff --git a/tests/ref/gradient-presets.png b/tests/ref/gradient-presets.png Binary files differnew file mode 100644 index 00000000..0c7fabdd --- /dev/null +++ b/tests/ref/gradient-presets.png diff --git a/tests/ref/gradient-radial-center.png b/tests/ref/gradient-radial-center.png Binary files differnew file mode 100644 index 00000000..e89e1f30 --- /dev/null +++ b/tests/ref/gradient-radial-center.png diff --git a/tests/ref/gradient-radial-focal-center-and-radius.png b/tests/ref/gradient-radial-focal-center-and-radius.png Binary files differnew file mode 100644 index 00000000..4bc8a5d6 --- /dev/null +++ b/tests/ref/gradient-radial-focal-center-and-radius.png diff --git a/tests/ref/gradient-radial-hsl.png b/tests/ref/gradient-radial-hsl.png Binary files differnew file mode 100644 index 00000000..4a2ded18 --- /dev/null +++ b/tests/ref/gradient-radial-hsl.png diff --git a/tests/ref/gradient-radial-radius.png b/tests/ref/gradient-radial-radius.png Binary files differnew file mode 100644 index 00000000..1037e63f --- /dev/null +++ b/tests/ref/gradient-radial-radius.png diff --git a/tests/ref/gradient-radial-relative-parent.png b/tests/ref/gradient-radial-relative-parent.png Binary files differnew file mode 100644 index 00000000..f8addbe0 --- /dev/null +++ b/tests/ref/gradient-radial-relative-parent.png diff --git a/tests/ref/gradient-radial-relative-self.png b/tests/ref/gradient-radial-relative-self.png Binary files differnew file mode 100644 index 00000000..f5fc6836 --- /dev/null +++ b/tests/ref/gradient-radial-relative-self.png diff --git a/tests/ref/gradient-radial-text.png b/tests/ref/gradient-radial-text.png Binary files differnew file mode 100644 index 00000000..6da09878 --- /dev/null +++ b/tests/ref/gradient-radial-text.png diff --git a/tests/ref/gradient-repr.png b/tests/ref/gradient-repr.png Binary files differnew file mode 100644 index 00000000..04908e59 --- /dev/null +++ b/tests/ref/gradient-repr.png diff --git a/tests/ref/gradient-text-decoration.png b/tests/ref/gradient-text-decoration.png Binary files differnew file mode 100644 index 00000000..d1713c99 --- /dev/null +++ b/tests/ref/gradient-text-decoration.png diff --git a/tests/ref/gradient-text-dir.png b/tests/ref/gradient-text-dir.png Binary files differnew file mode 100644 index 00000000..eab56d66 --- /dev/null +++ b/tests/ref/gradient-text-dir.png diff --git a/tests/ref/gradient-text-global.png b/tests/ref/gradient-text-global.png Binary files differnew file mode 100644 index 00000000..7892fbb2 --- /dev/null +++ b/tests/ref/gradient-text-global.png diff --git a/tests/ref/gradient-text-in-container.png b/tests/ref/gradient-text-in-container.png Binary files differnew file mode 100644 index 00000000..9122a556 --- /dev/null +++ b/tests/ref/gradient-text-in-container.png diff --git a/tests/ref/gradient-text-rotate.png b/tests/ref/gradient-text-rotate.png Binary files differnew file mode 100644 index 00000000..a32cacf8 --- /dev/null +++ b/tests/ref/gradient-text-rotate.png diff --git a/tests/ref/gradient-transformed.png b/tests/ref/gradient-transformed.png Binary files differnew file mode 100644 index 00000000..2ad1286e --- /dev/null +++ b/tests/ref/gradient-transformed.png diff --git a/tests/ref/grid-align.png b/tests/ref/grid-align.png Binary files differnew file mode 100644 index 00000000..f85abf69 --- /dev/null +++ b/tests/ref/grid-align.png diff --git a/tests/ref/grid-auto-shrink.png b/tests/ref/grid-auto-shrink.png Binary files differnew file mode 100644 index 00000000..27813e26 --- /dev/null +++ b/tests/ref/grid-auto-shrink.png diff --git a/tests/ref/grid-breaking-expand-vertically.png b/tests/ref/grid-breaking-expand-vertically.png Binary files differnew file mode 100644 index 00000000..14434d7c --- /dev/null +++ b/tests/ref/grid-breaking-expand-vertically.png diff --git a/tests/ref/grid-calendar.png b/tests/ref/grid-calendar.png Binary files differnew file mode 100644 index 00000000..0609b84f --- /dev/null +++ b/tests/ref/grid-calendar.png diff --git a/tests/ref/grid-cell-align-override.png b/tests/ref/grid-cell-align-override.png Binary files differnew file mode 100644 index 00000000..8ffde97f --- /dev/null +++ b/tests/ref/grid-cell-align-override.png diff --git a/tests/ref/grid-cell-breaking.png b/tests/ref/grid-cell-breaking.png Binary files differnew file mode 100644 index 00000000..c91a3993 --- /dev/null +++ b/tests/ref/grid-cell-breaking.png diff --git a/tests/ref/grid-cell-folding.png b/tests/ref/grid-cell-folding.png Binary files differnew file mode 100644 index 00000000..ce1108c6 --- /dev/null +++ b/tests/ref/grid-cell-folding.png diff --git a/tests/ref/grid-cell-override-in-header-and-footer-with-gutter.png b/tests/ref/grid-cell-override-in-header-and-footer-with-gutter.png Binary files differnew file mode 100644 index 00000000..a475bf90 --- /dev/null +++ b/tests/ref/grid-cell-override-in-header-and-footer-with-gutter.png diff --git a/tests/ref/grid-cell-override-in-header-and-footer.png b/tests/ref/grid-cell-override-in-header-and-footer.png Binary files differnew file mode 100644 index 00000000..4d31e379 --- /dev/null +++ b/tests/ref/grid-cell-override-in-header-and-footer.png diff --git a/tests/ref/grid-cell-override.png b/tests/ref/grid-cell-override.png Binary files differnew file mode 100644 index 00000000..d6f37d63 --- /dev/null +++ b/tests/ref/grid-cell-override.png diff --git a/tests/ref/grid-cell-position-automatic-skip-manual.png b/tests/ref/grid-cell-position-automatic-skip-manual.png Binary files differnew file mode 100644 index 00000000..ec615c97 --- /dev/null +++ b/tests/ref/grid-cell-position-automatic-skip-manual.png diff --git a/tests/ref/grid-cell-position-extra-rows.png b/tests/ref/grid-cell-position-extra-rows.png Binary files differnew file mode 100644 index 00000000..4d73c3f7 --- /dev/null +++ b/tests/ref/grid-cell-position-extra-rows.png diff --git a/tests/ref/grid-cell-position-out-of-order.png b/tests/ref/grid-cell-position-out-of-order.png Binary files differnew file mode 100644 index 00000000..d6bdad46 --- /dev/null +++ b/tests/ref/grid-cell-position-out-of-order.png diff --git a/tests/ref/grid-cell-position-partial.png b/tests/ref/grid-cell-position-partial.png Binary files differnew file mode 100644 index 00000000..3012c5b5 --- /dev/null +++ b/tests/ref/grid-cell-position-partial.png diff --git a/tests/ref/grid-cell-set.png b/tests/ref/grid-cell-set.png Binary files differnew file mode 100644 index 00000000..8795e53e --- /dev/null +++ b/tests/ref/grid-cell-set.png diff --git a/tests/ref/grid-cell-show-and-override.png b/tests/ref/grid-cell-show-and-override.png Binary files differnew file mode 100644 index 00000000..6af55596 --- /dev/null +++ b/tests/ref/grid-cell-show-and-override.png diff --git a/tests/ref/grid-cell-show-based-on-position.png b/tests/ref/grid-cell-show-based-on-position.png Binary files differnew file mode 100644 index 00000000..26ad6284 --- /dev/null +++ b/tests/ref/grid-cell-show-based-on-position.png diff --git a/tests/ref/grid-cell-show-emph.png b/tests/ref/grid-cell-show-emph.png Binary files differnew file mode 100644 index 00000000..bfc03d6d --- /dev/null +++ b/tests/ref/grid-cell-show-emph.png diff --git a/tests/ref/grid-cell-show-x-y.png b/tests/ref/grid-cell-show-x-y.png Binary files differnew file mode 100644 index 00000000..0fb4c2c5 --- /dev/null +++ b/tests/ref/grid-cell-show-x-y.png diff --git a/tests/ref/grid-cell-show.png b/tests/ref/grid-cell-show.png Binary files differnew file mode 100644 index 00000000..9ac6d269 --- /dev/null +++ b/tests/ref/grid-cell-show.png diff --git a/tests/ref/grid-cell-various-overrides.png b/tests/ref/grid-cell-various-overrides.png Binary files differnew file mode 100644 index 00000000..74490e84 --- /dev/null +++ b/tests/ref/grid-cell-various-overrides.png diff --git a/tests/ref/grid-colspan-gutter.png b/tests/ref/grid-colspan-gutter.png Binary files differnew file mode 100644 index 00000000..2ba9c217 --- /dev/null +++ b/tests/ref/grid-colspan-gutter.png diff --git a/tests/ref/grid-colspan-multiple-regions.png b/tests/ref/grid-colspan-multiple-regions.png Binary files differnew file mode 100644 index 00000000..22811aca --- /dev/null +++ b/tests/ref/grid-colspan-multiple-regions.png diff --git a/tests/ref/grid-colspan-over-all-fr-columns-page-width-auto.png b/tests/ref/grid-colspan-over-all-fr-columns-page-width-auto.png Binary files differnew file mode 100644 index 00000000..b5cf6cac --- /dev/null +++ b/tests/ref/grid-colspan-over-all-fr-columns-page-width-auto.png diff --git a/tests/ref/grid-colspan-over-all-fr-columns.png b/tests/ref/grid-colspan-over-all-fr-columns.png Binary files differnew file mode 100644 index 00000000..c152f3cc --- /dev/null +++ b/tests/ref/grid-colspan-over-all-fr-columns.png diff --git a/tests/ref/grid-colspan-over-some-fr-columns.png b/tests/ref/grid-colspan-over-some-fr-columns.png Binary files differnew file mode 100644 index 00000000..5d8157c2 --- /dev/null +++ b/tests/ref/grid-colspan-over-some-fr-columns.png diff --git a/tests/ref/grid-colspan-thick-stroke.png b/tests/ref/grid-colspan-thick-stroke.png Binary files differnew file mode 100644 index 00000000..7348551e --- /dev/null +++ b/tests/ref/grid-colspan-thick-stroke.png diff --git a/tests/ref/grid-colspan.png b/tests/ref/grid-colspan.png Binary files differnew file mode 100644 index 00000000..419d23b2 --- /dev/null +++ b/tests/ref/grid-colspan.png diff --git a/tests/ref/grid-column-sizing-auto-base.png b/tests/ref/grid-column-sizing-auto-base.png Binary files differnew file mode 100644 index 00000000..75664027 --- /dev/null +++ b/tests/ref/grid-column-sizing-auto-base.png diff --git a/tests/ref/grid-column-sizing-fr-base.png b/tests/ref/grid-column-sizing-fr-base.png Binary files differnew file mode 100644 index 00000000..d4a44be7 --- /dev/null +++ b/tests/ref/grid-column-sizing-fr-base.png diff --git a/tests/ref/grid-column-sizing-mixed-base.png b/tests/ref/grid-column-sizing-mixed-base.png Binary files differnew file mode 100644 index 00000000..dc92564d --- /dev/null +++ b/tests/ref/grid-column-sizing-mixed-base.png diff --git a/tests/ref/grid-columns-sizings-rect.png b/tests/ref/grid-columns-sizings-rect.png Binary files differnew file mode 100644 index 00000000..9381103d --- /dev/null +++ b/tests/ref/grid-columns-sizings-rect.png diff --git a/tests/ref/grid-complete-rows.png b/tests/ref/grid-complete-rows.png Binary files differnew file mode 100644 index 00000000..192aa911 --- /dev/null +++ b/tests/ref/grid-complete-rows.png diff --git a/tests/ref/grid-consecutive-rows-breaking.png b/tests/ref/grid-consecutive-rows-breaking.png Binary files differnew file mode 100644 index 00000000..6000271d --- /dev/null +++ b/tests/ref/grid-consecutive-rows-breaking.png diff --git a/tests/ref/grid-exam.png b/tests/ref/grid-exam.png Binary files differnew file mode 100644 index 00000000..97edd52e --- /dev/null +++ b/tests/ref/grid-exam.png diff --git a/tests/ref/grid-fill-func.png b/tests/ref/grid-fill-func.png Binary files differnew file mode 100644 index 00000000..388a52df --- /dev/null +++ b/tests/ref/grid-fill-func.png diff --git a/tests/ref/grid-finance.png b/tests/ref/grid-finance.png Binary files differnew file mode 100644 index 00000000..2ea48594 --- /dev/null +++ b/tests/ref/grid-finance.png diff --git a/tests/ref/grid-footer-bare-1.png b/tests/ref/grid-footer-bare-1.png Binary files differnew file mode 100644 index 00000000..e8c8b21a --- /dev/null +++ b/tests/ref/grid-footer-bare-1.png diff --git a/tests/ref/grid-footer-bare-2.png b/tests/ref/grid-footer-bare-2.png Binary files differnew file mode 100644 index 00000000..bad6a3dd --- /dev/null +++ b/tests/ref/grid-footer-bare-2.png diff --git a/tests/ref/grid-footer-below-rowspans.png b/tests/ref/grid-footer-below-rowspans.png Binary files differnew file mode 100644 index 00000000..5c3a2b26 --- /dev/null +++ b/tests/ref/grid-footer-below-rowspans.png diff --git a/tests/ref/grid-footer-cell-with-y.png b/tests/ref/grid-footer-cell-with-y.png Binary files differnew file mode 100644 index 00000000..3237ea69 --- /dev/null +++ b/tests/ref/grid-footer-cell-with-y.png diff --git a/tests/ref/grid-footer-expand.png b/tests/ref/grid-footer-expand.png Binary files differnew file mode 100644 index 00000000..118765d5 --- /dev/null +++ b/tests/ref/grid-footer-expand.png diff --git a/tests/ref/grid-footer-gutter-and-no-repeat.png b/tests/ref/grid-footer-gutter-and-no-repeat.png Binary files differnew file mode 100644 index 00000000..ea36ae03 --- /dev/null +++ b/tests/ref/grid-footer-gutter-and-no-repeat.png diff --git a/tests/ref/grid-footer-hline-and-vline-1.png b/tests/ref/grid-footer-hline-and-vline-1.png Binary files differnew file mode 100644 index 00000000..a4d9a681 --- /dev/null +++ b/tests/ref/grid-footer-hline-and-vline-1.png diff --git a/tests/ref/grid-footer-hline-and-vline-2.png b/tests/ref/grid-footer-hline-and-vline-2.png Binary files differnew file mode 100644 index 00000000..0ad2bacc --- /dev/null +++ b/tests/ref/grid-footer-hline-and-vline-2.png diff --git a/tests/ref/grid-footer-relative-row-sizes.png b/tests/ref/grid-footer-relative-row-sizes.png Binary files differnew file mode 100644 index 00000000..b533f13f --- /dev/null +++ b/tests/ref/grid-footer-relative-row-sizes.png diff --git a/tests/ref/grid-footer-rowspan.png b/tests/ref/grid-footer-rowspan.png Binary files differnew file mode 100644 index 00000000..369e4d07 --- /dev/null +++ b/tests/ref/grid-footer-rowspan.png diff --git a/tests/ref/grid-footer-stroke-edge-cases.png b/tests/ref/grid-footer-stroke-edge-cases.png Binary files differnew file mode 100644 index 00000000..c3db98e7 --- /dev/null +++ b/tests/ref/grid-footer-stroke-edge-cases.png diff --git a/tests/ref/grid-footer-top-stroke.png b/tests/ref/grid-footer-top-stroke.png Binary files differnew file mode 100644 index 00000000..ff9aa9f0 --- /dev/null +++ b/tests/ref/grid-footer-top-stroke.png diff --git a/tests/ref/grid-footer.png b/tests/ref/grid-footer.png Binary files differnew file mode 100644 index 00000000..196563c7 --- /dev/null +++ b/tests/ref/grid-footer.png diff --git a/tests/ref/grid-funcs-gutter.png b/tests/ref/grid-funcs-gutter.png Binary files differnew file mode 100644 index 00000000..ee6723ef --- /dev/null +++ b/tests/ref/grid-funcs-gutter.png diff --git a/tests/ref/grid-gutter-fr.png b/tests/ref/grid-gutter-fr.png Binary files differnew file mode 100644 index 00000000..2fce6949 --- /dev/null +++ b/tests/ref/grid-gutter-fr.png diff --git a/tests/ref/grid-header-and-footer-containing-rowspan.png b/tests/ref/grid-header-and-footer-containing-rowspan.png Binary files differnew file mode 100644 index 00000000..705d72a4 --- /dev/null +++ b/tests/ref/grid-header-and-footer-containing-rowspan.png diff --git a/tests/ref/grid-header-and-footer-empty.png b/tests/ref/grid-header-and-footer-empty.png Binary files differnew file mode 100644 index 00000000..c4e7bb0e --- /dev/null +++ b/tests/ref/grid-header-and-footer-empty.png diff --git a/tests/ref/grid-header-and-footer-lack-of-space.png b/tests/ref/grid-header-and-footer-lack-of-space.png Binary files differnew file mode 100644 index 00000000..78705776 --- /dev/null +++ b/tests/ref/grid-header-and-footer-lack-of-space.png diff --git a/tests/ref/grid-header-and-footer-orphan-prevention.png b/tests/ref/grid-header-and-footer-orphan-prevention.png Binary files differnew file mode 100644 index 00000000..8253b657 --- /dev/null +++ b/tests/ref/grid-header-and-footer-orphan-prevention.png diff --git a/tests/ref/grid-header-and-rowspan-non-contiguous-1.png b/tests/ref/grid-header-and-rowspan-non-contiguous-1.png Binary files differnew file mode 100644 index 00000000..d5088a12 --- /dev/null +++ b/tests/ref/grid-header-and-rowspan-non-contiguous-1.png diff --git a/tests/ref/grid-header-and-rowspan-non-contiguous-2.png b/tests/ref/grid-header-and-rowspan-non-contiguous-2.png Binary files differnew file mode 100644 index 00000000..4894d141 --- /dev/null +++ b/tests/ref/grid-header-and-rowspan-non-contiguous-2.png diff --git a/tests/ref/grid-header-and-rowspan-non-contiguous-3.png b/tests/ref/grid-header-and-rowspan-non-contiguous-3.png Binary files differnew file mode 100644 index 00000000..36e9a3c3 --- /dev/null +++ b/tests/ref/grid-header-and-rowspan-non-contiguous-3.png diff --git a/tests/ref/grid-header-block-with-fixed-height.png b/tests/ref/grid-header-block-with-fixed-height.png Binary files differnew file mode 100644 index 00000000..b7f2eedb --- /dev/null +++ b/tests/ref/grid-header-block-with-fixed-height.png diff --git a/tests/ref/grid-header-cell-with-y.png b/tests/ref/grid-header-cell-with-y.png Binary files differnew file mode 100644 index 00000000..e54e35fa --- /dev/null +++ b/tests/ref/grid-header-cell-with-y.png diff --git a/tests/ref/grid-header-containing-rowspan.png b/tests/ref/grid-header-containing-rowspan.png Binary files differnew file mode 100644 index 00000000..3cabff9e --- /dev/null +++ b/tests/ref/grid-header-containing-rowspan.png diff --git a/tests/ref/grid-header-empty.png b/tests/ref/grid-header-empty.png Binary files differnew file mode 100644 index 00000000..20e4d92c --- /dev/null +++ b/tests/ref/grid-header-empty.png diff --git a/tests/ref/grid-header-expand.png b/tests/ref/grid-header-expand.png Binary files differnew file mode 100644 index 00000000..46572441 --- /dev/null +++ b/tests/ref/grid-header-expand.png diff --git a/tests/ref/grid-header-footer-and-rowspan-non-contiguous-1.png b/tests/ref/grid-header-footer-and-rowspan-non-contiguous-1.png Binary files differnew file mode 100644 index 00000000..e7b153c8 --- /dev/null +++ b/tests/ref/grid-header-footer-and-rowspan-non-contiguous-1.png diff --git a/tests/ref/grid-header-footer-and-rowspan-non-contiguous-2.png b/tests/ref/grid-header-footer-and-rowspan-non-contiguous-2.png Binary files differnew file mode 100644 index 00000000..525475ac --- /dev/null +++ b/tests/ref/grid-header-footer-and-rowspan-non-contiguous-2.png diff --git a/tests/ref/grid-header-footer-block-with-fixed-height.png b/tests/ref/grid-header-footer-block-with-fixed-height.png Binary files differnew file mode 100644 index 00000000..1f2e7c20 --- /dev/null +++ b/tests/ref/grid-header-footer-block-with-fixed-height.png diff --git a/tests/ref/grid-header-hline-and-vline.png b/tests/ref/grid-header-hline-and-vline.png Binary files differnew file mode 100644 index 00000000..a01fc00b --- /dev/null +++ b/tests/ref/grid-header-hline-and-vline.png diff --git a/tests/ref/grid-header-hline-bottom-manually.png b/tests/ref/grid-header-hline-bottom-manually.png Binary files differnew file mode 100644 index 00000000..d944f7b5 --- /dev/null +++ b/tests/ref/grid-header-hline-bottom-manually.png diff --git a/tests/ref/grid-header-hline-bottom.png b/tests/ref/grid-header-hline-bottom.png Binary files differnew file mode 100644 index 00000000..f1361242 --- /dev/null +++ b/tests/ref/grid-header-hline-bottom.png diff --git a/tests/ref/grid-header-lack-of-space.png b/tests/ref/grid-header-lack-of-space.png Binary files differnew file mode 100644 index 00000000..4d2b483f --- /dev/null +++ b/tests/ref/grid-header-lack-of-space.png diff --git a/tests/ref/grid-header-last-child.png b/tests/ref/grid-header-last-child.png Binary files differnew file mode 100644 index 00000000..4fa1ff7c --- /dev/null +++ b/tests/ref/grid-header-last-child.png diff --git a/tests/ref/grid-header-nested.png b/tests/ref/grid-header-nested.png Binary files differnew file mode 100644 index 00000000..9078090f --- /dev/null +++ b/tests/ref/grid-header-nested.png diff --git a/tests/ref/grid-header-orphan-prevention.png b/tests/ref/grid-header-orphan-prevention.png Binary files differnew file mode 100644 index 00000000..fa903e42 --- /dev/null +++ b/tests/ref/grid-header-orphan-prevention.png diff --git a/tests/ref/grid-header-relative-row-sizes.png b/tests/ref/grid-header-relative-row-sizes.png Binary files differnew file mode 100644 index 00000000..69ed1d1e --- /dev/null +++ b/tests/ref/grid-header-relative-row-sizes.png diff --git a/tests/ref/grid-header-rowspan-base.png b/tests/ref/grid-header-rowspan-base.png Binary files differnew file mode 100644 index 00000000..1ab83591 --- /dev/null +++ b/tests/ref/grid-header-rowspan-base.png diff --git a/tests/ref/grid-header-stroke-edge-cases.png b/tests/ref/grid-header-stroke-edge-cases.png Binary files differnew file mode 100644 index 00000000..b86eb632 --- /dev/null +++ b/tests/ref/grid-header-stroke-edge-cases.png diff --git a/tests/ref/grid-headers-gutter.png b/tests/ref/grid-headers-gutter.png Binary files differnew file mode 100644 index 00000000..c2a48a66 --- /dev/null +++ b/tests/ref/grid-headers-gutter.png diff --git a/tests/ref/grid-headers-no-repeat.png b/tests/ref/grid-headers-no-repeat.png Binary files differnew file mode 100644 index 00000000..32d281a1 --- /dev/null +++ b/tests/ref/grid-headers-no-repeat.png diff --git a/tests/ref/grid-headers.png b/tests/ref/grid-headers.png Binary files differnew file mode 100644 index 00000000..13e88dbe --- /dev/null +++ b/tests/ref/grid-headers.png diff --git a/tests/ref/grid-inset-folding.png b/tests/ref/grid-inset-folding.png Binary files differnew file mode 100644 index 00000000..7f994264 --- /dev/null +++ b/tests/ref/grid-inset-folding.png diff --git a/tests/ref/grid-inset.png b/tests/ref/grid-inset.png Binary files differnew file mode 100644 index 00000000..d31197d0 --- /dev/null +++ b/tests/ref/grid-inset.png diff --git a/tests/ref/grid-nested-breaking.png b/tests/ref/grid-nested-breaking.png Binary files differnew file mode 100644 index 00000000..b203c230 --- /dev/null +++ b/tests/ref/grid-nested-breaking.png diff --git a/tests/ref/grid-nested-footers.png b/tests/ref/grid-nested-footers.png Binary files differnew file mode 100644 index 00000000..1af85a00 --- /dev/null +++ b/tests/ref/grid-nested-footers.png diff --git a/tests/ref/grid-nested-headers.png b/tests/ref/grid-nested-headers.png Binary files differnew file mode 100644 index 00000000..e714dcc4 --- /dev/null +++ b/tests/ref/grid-nested-headers.png diff --git a/tests/ref/grid-nested-with-footers.png b/tests/ref/grid-nested-with-footers.png Binary files differnew file mode 100644 index 00000000..5ceae877 --- /dev/null +++ b/tests/ref/grid-nested-with-footers.png diff --git a/tests/ref/grid-nested-with-headers.png b/tests/ref/grid-nested-with-headers.png Binary files differnew file mode 100644 index 00000000..6b7ef14b --- /dev/null +++ b/tests/ref/grid-nested-with-headers.png diff --git a/tests/ref/grid-row-sizing-manual-align.png b/tests/ref/grid-row-sizing-manual-align.png Binary files differnew file mode 100644 index 00000000..68b0911e --- /dev/null +++ b/tests/ref/grid-row-sizing-manual-align.png diff --git a/tests/ref/grid-rowspan-block-full-height.png b/tests/ref/grid-rowspan-block-full-height.png Binary files differnew file mode 100644 index 00000000..078cbda4 --- /dev/null +++ b/tests/ref/grid-rowspan-block-full-height.png diff --git a/tests/ref/grid-rowspan-block-overflow.png b/tests/ref/grid-rowspan-block-overflow.png Binary files differnew file mode 100644 index 00000000..78e26d72 --- /dev/null +++ b/tests/ref/grid-rowspan-block-overflow.png diff --git a/tests/ref/grid-rowspan-cell-coordinates.png b/tests/ref/grid-rowspan-cell-coordinates.png Binary files differnew file mode 100644 index 00000000..ebe19fd4 --- /dev/null +++ b/tests/ref/grid-rowspan-cell-coordinates.png diff --git a/tests/ref/grid-rowspan-cell-order.png b/tests/ref/grid-rowspan-cell-order.png Binary files differnew file mode 100644 index 00000000..c9b1f554 --- /dev/null +++ b/tests/ref/grid-rowspan-cell-order.png diff --git a/tests/ref/grid-rowspan-excessive-gutter.png b/tests/ref/grid-rowspan-excessive-gutter.png Binary files differnew file mode 100644 index 00000000..8688364c --- /dev/null +++ b/tests/ref/grid-rowspan-excessive-gutter.png diff --git a/tests/ref/grid-rowspan-excessive.png b/tests/ref/grid-rowspan-excessive.png Binary files differnew file mode 100644 index 00000000..1e6b4128 --- /dev/null +++ b/tests/ref/grid-rowspan-excessive.png diff --git a/tests/ref/grid-rowspan-fixed-size.png b/tests/ref/grid-rowspan-fixed-size.png Binary files differnew file mode 100644 index 00000000..c9ae3fa1 --- /dev/null +++ b/tests/ref/grid-rowspan-fixed-size.png diff --git a/tests/ref/grid-rowspan-gutter.png b/tests/ref/grid-rowspan-gutter.png Binary files differnew file mode 100644 index 00000000..b37a1cab --- /dev/null +++ b/tests/ref/grid-rowspan-gutter.png diff --git a/tests/ref/grid-rowspan-in-all-columns-stroke-gutter.png b/tests/ref/grid-rowspan-in-all-columns-stroke-gutter.png Binary files differnew file mode 100644 index 00000000..edad2f01 --- /dev/null +++ b/tests/ref/grid-rowspan-in-all-columns-stroke-gutter.png diff --git a/tests/ref/grid-rowspan-in-all-columns-stroke.png b/tests/ref/grid-rowspan-in-all-columns-stroke.png Binary files differnew file mode 100644 index 00000000..135d1911 --- /dev/null +++ b/tests/ref/grid-rowspan-in-all-columns-stroke.png diff --git a/tests/ref/grid-rowspan-over-auto-row.png b/tests/ref/grid-rowspan-over-auto-row.png Binary files differnew file mode 100644 index 00000000..45037382 --- /dev/null +++ b/tests/ref/grid-rowspan-over-auto-row.png diff --git a/tests/ref/grid-rowspan-over-fr-row-at-end.png b/tests/ref/grid-rowspan-over-fr-row-at-end.png Binary files differnew file mode 100644 index 00000000..1cf8b9fc --- /dev/null +++ b/tests/ref/grid-rowspan-over-fr-row-at-end.png diff --git a/tests/ref/grid-rowspan-over-fr-row-at-start.png b/tests/ref/grid-rowspan-over-fr-row-at-start.png Binary files differnew file mode 100644 index 00000000..577db916 --- /dev/null +++ b/tests/ref/grid-rowspan-over-fr-row-at-start.png diff --git a/tests/ref/grid-rowspan-split-1.png b/tests/ref/grid-rowspan-split-1.png Binary files differnew file mode 100644 index 00000000..e99b105f --- /dev/null +++ b/tests/ref/grid-rowspan-split-1.png diff --git a/tests/ref/grid-rowspan-split-10.png b/tests/ref/grid-rowspan-split-10.png Binary files differnew file mode 100644 index 00000000..0b907e7d --- /dev/null +++ b/tests/ref/grid-rowspan-split-10.png diff --git a/tests/ref/grid-rowspan-split-11.png b/tests/ref/grid-rowspan-split-11.png Binary files differnew file mode 100644 index 00000000..202665d6 --- /dev/null +++ b/tests/ref/grid-rowspan-split-11.png diff --git a/tests/ref/grid-rowspan-split-12.png b/tests/ref/grid-rowspan-split-12.png Binary files differnew file mode 100644 index 00000000..3d8985f2 --- /dev/null +++ b/tests/ref/grid-rowspan-split-12.png diff --git a/tests/ref/grid-rowspan-split-13.png b/tests/ref/grid-rowspan-split-13.png Binary files differnew file mode 100644 index 00000000..f4e9d694 --- /dev/null +++ b/tests/ref/grid-rowspan-split-13.png diff --git a/tests/ref/grid-rowspan-split-14.png b/tests/ref/grid-rowspan-split-14.png Binary files differnew file mode 100644 index 00000000..1500a89b --- /dev/null +++ b/tests/ref/grid-rowspan-split-14.png diff --git a/tests/ref/grid-rowspan-split-15.png b/tests/ref/grid-rowspan-split-15.png Binary files differnew file mode 100644 index 00000000..445f0a95 --- /dev/null +++ b/tests/ref/grid-rowspan-split-15.png diff --git a/tests/ref/grid-rowspan-split-16.png b/tests/ref/grid-rowspan-split-16.png Binary files differnew file mode 100644 index 00000000..fff83aeb --- /dev/null +++ b/tests/ref/grid-rowspan-split-16.png diff --git a/tests/ref/grid-rowspan-split-17.png b/tests/ref/grid-rowspan-split-17.png Binary files differnew file mode 100644 index 00000000..2224c194 --- /dev/null +++ b/tests/ref/grid-rowspan-split-17.png diff --git a/tests/ref/grid-rowspan-split-2.png b/tests/ref/grid-rowspan-split-2.png Binary files differnew file mode 100644 index 00000000..43a5eed7 --- /dev/null +++ b/tests/ref/grid-rowspan-split-2.png diff --git a/tests/ref/grid-rowspan-split-3.png b/tests/ref/grid-rowspan-split-3.png Binary files differnew file mode 100644 index 00000000..0d7c3359 --- /dev/null +++ b/tests/ref/grid-rowspan-split-3.png diff --git a/tests/ref/grid-rowspan-split-4.png b/tests/ref/grid-rowspan-split-4.png Binary files differnew file mode 100644 index 00000000..2af887bb --- /dev/null +++ b/tests/ref/grid-rowspan-split-4.png diff --git a/tests/ref/grid-rowspan-split-5.png b/tests/ref/grid-rowspan-split-5.png Binary files differnew file mode 100644 index 00000000..3aa79cda --- /dev/null +++ b/tests/ref/grid-rowspan-split-5.png diff --git a/tests/ref/grid-rowspan-split-6.png b/tests/ref/grid-rowspan-split-6.png Binary files differnew file mode 100644 index 00000000..fbf5bf28 --- /dev/null +++ b/tests/ref/grid-rowspan-split-6.png diff --git a/tests/ref/grid-rowspan-split-7.png b/tests/ref/grid-rowspan-split-7.png Binary files differnew file mode 100644 index 00000000..00e03f02 --- /dev/null +++ b/tests/ref/grid-rowspan-split-7.png diff --git a/tests/ref/grid-rowspan-split-8.png b/tests/ref/grid-rowspan-split-8.png Binary files differnew file mode 100644 index 00000000..405b5423 --- /dev/null +++ b/tests/ref/grid-rowspan-split-8.png diff --git a/tests/ref/grid-rowspan-split-9.png b/tests/ref/grid-rowspan-split-9.png Binary files differnew file mode 100644 index 00000000..5346be71 --- /dev/null +++ b/tests/ref/grid-rowspan-split-9.png diff --git a/tests/ref/grid-rowspan-unbreakable-1.png b/tests/ref/grid-rowspan-unbreakable-1.png Binary files differnew file mode 100644 index 00000000..6112c069 --- /dev/null +++ b/tests/ref/grid-rowspan-unbreakable-1.png diff --git a/tests/ref/grid-rowspan-unbreakable-2.png b/tests/ref/grid-rowspan-unbreakable-2.png Binary files differnew file mode 100644 index 00000000..8e4a222a --- /dev/null +++ b/tests/ref/grid-rowspan-unbreakable-2.png diff --git a/tests/ref/grid-rowspan.png b/tests/ref/grid-rowspan.png Binary files differnew file mode 100644 index 00000000..87ad4180 --- /dev/null +++ b/tests/ref/grid-rowspan.png diff --git a/tests/ref/grid-rtl-colspan-stroke.png b/tests/ref/grid-rtl-colspan-stroke.png Binary files differnew file mode 100644 index 00000000..248a575c --- /dev/null +++ b/tests/ref/grid-rtl-colspan-stroke.png diff --git a/tests/ref/grid-rtl-colspan.png b/tests/ref/grid-rtl-colspan.png Binary files differnew file mode 100644 index 00000000..886e276d --- /dev/null +++ b/tests/ref/grid-rtl-colspan.png diff --git a/tests/ref/grid-rtl-complex.png b/tests/ref/grid-rtl-complex.png Binary files differnew file mode 100644 index 00000000..a4177548 --- /dev/null +++ b/tests/ref/grid-rtl-complex.png diff --git a/tests/ref/grid-rtl-header.png b/tests/ref/grid-rtl-header.png Binary files differnew file mode 100644 index 00000000..1ed532c3 --- /dev/null +++ b/tests/ref/grid-rtl-header.png diff --git a/tests/ref/grid-rtl-multiple-regions.png b/tests/ref/grid-rtl-multiple-regions.png Binary files differnew file mode 100644 index 00000000..a9ec7340 --- /dev/null +++ b/tests/ref/grid-rtl-multiple-regions.png diff --git a/tests/ref/grid-rtl-rowspan.png b/tests/ref/grid-rtl-rowspan.png Binary files differnew file mode 100644 index 00000000..2465164b --- /dev/null +++ b/tests/ref/grid-rtl-rowspan.png diff --git a/tests/ref/grid-rtl-vline-position.png b/tests/ref/grid-rtl-vline-position.png Binary files differnew file mode 100644 index 00000000..3612fc9f --- /dev/null +++ b/tests/ref/grid-rtl-vline-position.png diff --git a/tests/ref/grid-rtl.png b/tests/ref/grid-rtl.png Binary files differnew file mode 100644 index 00000000..c40fc588 --- /dev/null +++ b/tests/ref/grid-rtl.png diff --git a/tests/ref/grid-same-row-multiple-columns-breaking.png b/tests/ref/grid-same-row-multiple-columns-breaking.png Binary files differnew file mode 100644 index 00000000..b440f336 --- /dev/null +++ b/tests/ref/grid-same-row-multiple-columns-breaking.png diff --git a/tests/ref/grid-stroke-array.png b/tests/ref/grid-stroke-array.png Binary files differnew file mode 100644 index 00000000..6f8e28b0 --- /dev/null +++ b/tests/ref/grid-stroke-array.png diff --git a/tests/ref/grid-stroke-automatically-positioned-lines.png b/tests/ref/grid-stroke-automatically-positioned-lines.png Binary files differnew file mode 100644 index 00000000..2118112c --- /dev/null +++ b/tests/ref/grid-stroke-automatically-positioned-lines.png diff --git a/tests/ref/grid-stroke-border-partial.png b/tests/ref/grid-stroke-border-partial.png Binary files differnew file mode 100644 index 00000000..ffd8835f --- /dev/null +++ b/tests/ref/grid-stroke-border-partial.png diff --git a/tests/ref/grid-stroke-complex.png b/tests/ref/grid-stroke-complex.png Binary files differnew file mode 100644 index 00000000..e68fd5f3 --- /dev/null +++ b/tests/ref/grid-stroke-complex.png diff --git a/tests/ref/grid-stroke-field-in-show.png b/tests/ref/grid-stroke-field-in-show.png Binary files differnew file mode 100644 index 00000000..695868c0 --- /dev/null +++ b/tests/ref/grid-stroke-field-in-show.png diff --git a/tests/ref/grid-stroke-folding.png b/tests/ref/grid-stroke-folding.png Binary files differnew file mode 100644 index 00000000..0f2d5960 --- /dev/null +++ b/tests/ref/grid-stroke-folding.png diff --git a/tests/ref/grid-stroke-func.png b/tests/ref/grid-stroke-func.png Binary files differnew file mode 100644 index 00000000..954e90df --- /dev/null +++ b/tests/ref/grid-stroke-func.png diff --git a/tests/ref/grid-stroke-hline-position-bottom-gutter.png b/tests/ref/grid-stroke-hline-position-bottom-gutter.png Binary files differnew file mode 100644 index 00000000..23c7def4 --- /dev/null +++ b/tests/ref/grid-stroke-hline-position-bottom-gutter.png diff --git a/tests/ref/grid-stroke-hline-position-bottom.png b/tests/ref/grid-stroke-hline-position-bottom.png Binary files differnew file mode 100644 index 00000000..25c003c8 --- /dev/null +++ b/tests/ref/grid-stroke-hline-position-bottom.png diff --git a/tests/ref/grid-stroke-hline-rowspan.png b/tests/ref/grid-stroke-hline-rowspan.png Binary files differnew file mode 100644 index 00000000..2faf7079 --- /dev/null +++ b/tests/ref/grid-stroke-hline-rowspan.png diff --git a/tests/ref/grid-stroke-manually-positioned-lines.png b/tests/ref/grid-stroke-manually-positioned-lines.png Binary files differnew file mode 100644 index 00000000..a8a75ee0 --- /dev/null +++ b/tests/ref/grid-stroke-manually-positioned-lines.png diff --git a/tests/ref/grid-stroke-none.png b/tests/ref/grid-stroke-none.png Binary files differnew file mode 100644 index 00000000..3f978bd3 --- /dev/null +++ b/tests/ref/grid-stroke-none.png diff --git a/tests/ref/grid-stroke-pattern.png b/tests/ref/grid-stroke-pattern.png Binary files differnew file mode 100644 index 00000000..15e846ea --- /dev/null +++ b/tests/ref/grid-stroke-pattern.png diff --git a/tests/ref/grid-stroke-priority-cell.png b/tests/ref/grid-stroke-priority-cell.png Binary files differnew file mode 100644 index 00000000..2c28e9e8 --- /dev/null +++ b/tests/ref/grid-stroke-priority-cell.png diff --git a/tests/ref/grid-stroke-priority-line-cell.png b/tests/ref/grid-stroke-priority-line-cell.png Binary files differnew file mode 100644 index 00000000..064dc1c9 --- /dev/null +++ b/tests/ref/grid-stroke-priority-line-cell.png diff --git a/tests/ref/grid-stroke-priority-line.png b/tests/ref/grid-stroke-priority-line.png Binary files differnew file mode 100644 index 00000000..1bcaa2ee --- /dev/null +++ b/tests/ref/grid-stroke-priority-line.png diff --git a/tests/ref/grid-stroke-set-on-cell-and-line.png b/tests/ref/grid-stroke-set-on-cell-and-line.png Binary files differnew file mode 100644 index 00000000..d43752f0 --- /dev/null +++ b/tests/ref/grid-stroke-set-on-cell-and-line.png diff --git a/tests/ref/grid-stroke-vline-colspan.png b/tests/ref/grid-stroke-vline-colspan.png Binary files differnew file mode 100644 index 00000000..7b381437 --- /dev/null +++ b/tests/ref/grid-stroke-vline-colspan.png diff --git a/tests/ref/grid-stroke-vline-position-left-and-right.png b/tests/ref/grid-stroke-vline-position-left-and-right.png Binary files differnew file mode 100644 index 00000000..852fcf29 --- /dev/null +++ b/tests/ref/grid-stroke-vline-position-left-and-right.png diff --git a/tests/ref/grid-trailing-linebreak-region-overflow.png b/tests/ref/grid-trailing-linebreak-region-overflow.png Binary files differnew file mode 100644 index 00000000..4f7bc852 --- /dev/null +++ b/tests/ref/grid-trailing-linebreak-region-overflow.png diff --git a/tests/ref/heading-basic.png b/tests/ref/heading-basic.png Binary files differnew file mode 100644 index 00000000..74a8f2ce --- /dev/null +++ b/tests/ref/heading-basic.png diff --git a/tests/ref/heading-block.png b/tests/ref/heading-block.png Binary files differnew file mode 100644 index 00000000..595f18f5 --- /dev/null +++ b/tests/ref/heading-block.png diff --git a/tests/ref/heading-offset-and-level.png b/tests/ref/heading-offset-and-level.png Binary files differnew file mode 100644 index 00000000..9277e770 --- /dev/null +++ b/tests/ref/heading-offset-and-level.png diff --git a/tests/ref/heading-offset.png b/tests/ref/heading-offset.png Binary files differnew file mode 100644 index 00000000..3a3670cc --- /dev/null +++ b/tests/ref/heading-offset.png diff --git a/tests/ref/heading-show-where.png b/tests/ref/heading-show-where.png Binary files differnew file mode 100644 index 00000000..609e6ec9 --- /dev/null +++ b/tests/ref/heading-show-where.png diff --git a/tests/ref/heading-syntax-at-start.png b/tests/ref/heading-syntax-at-start.png Binary files differnew file mode 100644 index 00000000..29b824e0 --- /dev/null +++ b/tests/ref/heading-syntax-at-start.png diff --git a/tests/ref/heading-syntax-edge-cases.png b/tests/ref/heading-syntax-edge-cases.png Binary files differnew file mode 100644 index 00000000..372e1a65 --- /dev/null +++ b/tests/ref/heading-syntax-edge-cases.png diff --git a/tests/ref/hide-image.png b/tests/ref/hide-image.png Binary files differnew file mode 100644 index 00000000..78bc690c --- /dev/null +++ b/tests/ref/hide-image.png diff --git a/tests/ref/hide-line.png b/tests/ref/hide-line.png Binary files differnew file mode 100644 index 00000000..7d8fa6cd --- /dev/null +++ b/tests/ref/hide-line.png diff --git a/tests/ref/hide-list.png b/tests/ref/hide-list.png Binary files differnew file mode 100644 index 00000000..055f7b66 --- /dev/null +++ b/tests/ref/hide-list.png diff --git a/tests/ref/hide-polygon.png b/tests/ref/hide-polygon.png Binary files differnew file mode 100644 index 00000000..5c74eb41 --- /dev/null +++ b/tests/ref/hide-polygon.png diff --git a/tests/ref/hide-rect.png b/tests/ref/hide-rect.png Binary files differnew file mode 100644 index 00000000..62372c21 --- /dev/null +++ b/tests/ref/hide-rect.png diff --git a/tests/ref/hide-table.png b/tests/ref/hide-table.png Binary files differnew file mode 100644 index 00000000..e3d890d7 --- /dev/null +++ b/tests/ref/hide-table.png diff --git a/tests/ref/hide-text.png b/tests/ref/hide-text.png Binary files differnew file mode 100644 index 00000000..1136038c --- /dev/null +++ b/tests/ref/hide-text.png diff --git a/tests/ref/highlight-bounds.png b/tests/ref/highlight-bounds.png Binary files differnew file mode 100644 index 00000000..ed868c29 --- /dev/null +++ b/tests/ref/highlight-bounds.png diff --git a/tests/ref/highlight-edges-bounds.png b/tests/ref/highlight-edges-bounds.png Binary files differnew file mode 100644 index 00000000..f78f3cc3 --- /dev/null +++ b/tests/ref/highlight-edges-bounds.png diff --git a/tests/ref/highlight-edges.png b/tests/ref/highlight-edges.png Binary files differnew file mode 100644 index 00000000..ca48707f --- /dev/null +++ b/tests/ref/highlight-edges.png diff --git a/tests/ref/highlight-radius.png b/tests/ref/highlight-radius.png Binary files differnew file mode 100644 index 00000000..3baa3e6d --- /dev/null +++ b/tests/ref/highlight-radius.png diff --git a/tests/ref/highlight-stroke.png b/tests/ref/highlight-stroke.png Binary files differnew file mode 100644 index 00000000..5a8ad3b5 --- /dev/null +++ b/tests/ref/highlight-stroke.png diff --git a/tests/ref/highlight.png b/tests/ref/highlight.png Binary files differnew file mode 100644 index 00000000..0047b7f4 --- /dev/null +++ b/tests/ref/highlight.png diff --git a/tests/ref/hyphenate-between-shape-runs.png b/tests/ref/hyphenate-between-shape-runs.png Binary files differnew file mode 100644 index 00000000..a365af24 --- /dev/null +++ b/tests/ref/hyphenate-between-shape-runs.png diff --git a/tests/ref/hyphenate-off-temporarily.png b/tests/ref/hyphenate-off-temporarily.png Binary files differnew file mode 100644 index 00000000..48e3caa9 --- /dev/null +++ b/tests/ref/hyphenate-off-temporarily.png diff --git a/tests/ref/hyphenate-punctuation.png b/tests/ref/hyphenate-punctuation.png Binary files differnew file mode 100644 index 00000000..897a15a0 --- /dev/null +++ b/tests/ref/hyphenate-punctuation.png diff --git a/tests/ref/hyphenate-shy.png b/tests/ref/hyphenate-shy.png Binary files differnew file mode 100644 index 00000000..a548c711 --- /dev/null +++ b/tests/ref/hyphenate-shy.png diff --git a/tests/ref/hyphenate.png b/tests/ref/hyphenate.png Binary files differnew file mode 100644 index 00000000..c01c9021 --- /dev/null +++ b/tests/ref/hyphenate.png diff --git a/tests/ref/if-condition-complex.png b/tests/ref/if-condition-complex.png Binary files differnew file mode 100644 index 00000000..4cbebc5e --- /dev/null +++ b/tests/ref/if-condition-complex.png diff --git a/tests/ref/if-markup.png b/tests/ref/if-markup.png Binary files differnew file mode 100644 index 00000000..57eb47da --- /dev/null +++ b/tests/ref/if-markup.png diff --git a/tests/ref/image-baseline-with-box.png b/tests/ref/image-baseline-with-box.png Binary files differnew file mode 100644 index 00000000..41128069 --- /dev/null +++ b/tests/ref/image-baseline-with-box.png diff --git a/tests/ref/image-decode-detect-format.png b/tests/ref/image-decode-detect-format.png Binary files differnew file mode 100644 index 00000000..6f12e8b4 --- /dev/null +++ b/tests/ref/image-decode-detect-format.png diff --git a/tests/ref/image-decode-specify-format.png b/tests/ref/image-decode-specify-format.png Binary files differnew file mode 100644 index 00000000..6f12e8b4 --- /dev/null +++ b/tests/ref/image-decode-specify-format.png diff --git a/tests/ref/image-decode-svg.png b/tests/ref/image-decode-svg.png Binary files differnew file mode 100644 index 00000000..b7cfcb17 --- /dev/null +++ b/tests/ref/image-decode-svg.png diff --git a/tests/ref/image-fit.png b/tests/ref/image-fit.png Binary files differnew file mode 100644 index 00000000..5a3bdec1 --- /dev/null +++ b/tests/ref/image-fit.png diff --git a/tests/ref/image-jump-to-next-page.png b/tests/ref/image-jump-to-next-page.png Binary files differnew file mode 100644 index 00000000..d8f03b3f --- /dev/null +++ b/tests/ref/image-jump-to-next-page.png diff --git a/tests/ref/image-natural-dpi-sizing.png b/tests/ref/image-natural-dpi-sizing.png Binary files differnew file mode 100644 index 00000000..3b9f3fa5 --- /dev/null +++ b/tests/ref/image-natural-dpi-sizing.png diff --git a/tests/ref/image-rgba-png-and-jpeg.png b/tests/ref/image-rgba-png-and-jpeg.png Binary files differnew file mode 100644 index 00000000..60127170 --- /dev/null +++ b/tests/ref/image-rgba-png-and-jpeg.png diff --git a/tests/ref/image-sizing.png b/tests/ref/image-sizing.png Binary files differnew file mode 100644 index 00000000..7419de14 --- /dev/null +++ b/tests/ref/image-sizing.png diff --git a/tests/ref/image-svg-complex.png b/tests/ref/image-svg-complex.png Binary files differnew file mode 100644 index 00000000..1ac45477 --- /dev/null +++ b/tests/ref/image-svg-complex.png diff --git a/tests/ref/image-svg-text-font.png b/tests/ref/image-svg-text-font.png Binary files differnew file mode 100644 index 00000000..2e3b0a0f --- /dev/null +++ b/tests/ref/image-svg-text-font.png diff --git a/tests/ref/image-svg-text.png b/tests/ref/image-svg-text.png Binary files differnew file mode 100644 index 00000000..2e41f905 --- /dev/null +++ b/tests/ref/image-svg-text.png diff --git a/tests/ref/import-basic.png b/tests/ref/import-basic.png Binary files differnew file mode 100644 index 00000000..674c4ecf --- /dev/null +++ b/tests/ref/import-basic.png diff --git a/tests/ref/import-from-function-scope.png b/tests/ref/import-from-function-scope.png Binary files differnew file mode 100644 index 00000000..f6169d8c --- /dev/null +++ b/tests/ref/import-from-function-scope.png diff --git a/tests/ref/import-source-field-access.png b/tests/ref/import-source-field-access.png Binary files differnew file mode 100644 index 00000000..e42bf209 --- /dev/null +++ b/tests/ref/import-source-field-access.png diff --git a/tests/ref/include-file.png b/tests/ref/include-file.png Binary files differnew file mode 100644 index 00000000..57c3aca1 --- /dev/null +++ b/tests/ref/include-file.png diff --git a/tests/ref/int-display.png b/tests/ref/int-display.png Binary files differnew file mode 100644 index 00000000..bfb04648 --- /dev/null +++ b/tests/ref/int-display.png diff --git a/tests/ref/int-repr.png b/tests/ref/int-repr.png Binary files differnew file mode 100644 index 00000000..a2ee4ee0 --- /dev/null +++ b/tests/ref/int-repr.png diff --git a/tests/ref/issue-1041-smartquotes-in-outline.png b/tests/ref/issue-1041-smartquotes-in-outline.png Binary files differnew file mode 100644 index 00000000..29ba4065 --- /dev/null +++ b/tests/ref/issue-1041-smartquotes-in-outline.png diff --git a/tests/ref/issue-1050-terms-indent.png b/tests/ref/issue-1050-terms-indent.png Binary files differnew file mode 100644 index 00000000..ca0521c7 --- /dev/null +++ b/tests/ref/issue-1050-terms-indent.png diff --git a/tests/ref/issue-1052-math-number-spacing.png b/tests/ref/issue-1052-math-number-spacing.png Binary files differnew file mode 100644 index 00000000..79df2c9f --- /dev/null +++ b/tests/ref/issue-1052-math-number-spacing.png diff --git a/tests/ref/issue-1216-clamp-panic.png b/tests/ref/issue-1216-clamp-panic.png Binary files differnew file mode 100644 index 00000000..d51f134c --- /dev/null +++ b/tests/ref/issue-1216-clamp-panic.png diff --git a/tests/ref/issue-1240-stack-h-fr.png b/tests/ref/issue-1240-stack-h-fr.png Binary files differnew file mode 100644 index 00000000..ae1ba41e --- /dev/null +++ b/tests/ref/issue-1240-stack-h-fr.png diff --git a/tests/ref/issue-1240-stack-v-fr.png b/tests/ref/issue-1240-stack-v-fr.png Binary files differnew file mode 100644 index 00000000..a9ac36e8 --- /dev/null +++ b/tests/ref/issue-1240-stack-v-fr.png diff --git a/tests/ref/issue-1368-place-pagebreak.png b/tests/ref/issue-1368-place-pagebreak.png Binary files differnew file mode 100644 index 00000000..920cd203 --- /dev/null +++ b/tests/ref/issue-1368-place-pagebreak.png diff --git a/tests/ref/issue-1373-bidi-tofus.png b/tests/ref/issue-1373-bidi-tofus.png Binary files differnew file mode 100644 index 00000000..783eb473 --- /dev/null +++ b/tests/ref/issue-1373-bidi-tofus.png diff --git a/tests/ref/issue-1388-table-row-missing.png b/tests/ref/issue-1388-table-row-missing.png Binary files differnew file mode 100644 index 00000000..dd08eb46 --- /dev/null +++ b/tests/ref/issue-1388-table-row-missing.png diff --git a/tests/ref/issue-1398-line-align.png b/tests/ref/issue-1398-line-align.png Binary files differnew file mode 100644 index 00000000..778aa72c --- /dev/null +++ b/tests/ref/issue-1398-line-align.png diff --git a/tests/ref/issue-1433-footnote-in-list.png b/tests/ref/issue-1433-footnote-in-list.png Binary files differnew file mode 100644 index 00000000..28a6e77f --- /dev/null +++ b/tests/ref/issue-1433-footnote-in-list.png diff --git a/tests/ref/issue-1540-smartquotes-across-newlines.png b/tests/ref/issue-1540-smartquotes-across-newlines.png Binary files differnew file mode 100644 index 00000000..10fe7337 --- /dev/null +++ b/tests/ref/issue-1540-smartquotes-across-newlines.png diff --git a/tests/ref/issue-1597-cite-footnote.png b/tests/ref/issue-1597-cite-footnote.png Binary files differnew file mode 100644 index 00000000..bdd9f225 --- /dev/null +++ b/tests/ref/issue-1597-cite-footnote.png diff --git a/tests/ref/issue-1825-rect-overflow.png b/tests/ref/issue-1825-rect-overflow.png Binary files differnew file mode 100644 index 00000000..70f09e12 --- /dev/null +++ b/tests/ref/issue-1825-rect-overflow.png diff --git a/tests/ref/issue-183-table-lines.png b/tests/ref/issue-183-table-lines.png Binary files differnew file mode 100644 index 00000000..e4369262 --- /dev/null +++ b/tests/ref/issue-183-table-lines.png diff --git a/tests/ref/issue-1948-math-text-break.png b/tests/ref/issue-1948-math-text-break.png Binary files differnew file mode 100644 index 00000000..6e3e9e85 --- /dev/null +++ b/tests/ref/issue-1948-math-text-break.png diff --git a/tests/ref/issue-2044-invalid-parsed-ident.png b/tests/ref/issue-2044-invalid-parsed-ident.png Binary files differnew file mode 100644 index 00000000..7e37ce2c --- /dev/null +++ b/tests/ref/issue-2044-invalid-parsed-ident.png diff --git a/tests/ref/issue-2051-new-cm-svg.png b/tests/ref/issue-2051-new-cm-svg.png Binary files differnew file mode 100644 index 00000000..65352860 --- /dev/null +++ b/tests/ref/issue-2051-new-cm-svg.png diff --git a/tests/ref/issue-2055-math-eval.png b/tests/ref/issue-2055-math-eval.png Binary files differnew file mode 100644 index 00000000..168b8913 --- /dev/null +++ b/tests/ref/issue-2055-math-eval.png diff --git a/tests/ref/issue-2095-pagebreak-numbering.png b/tests/ref/issue-2095-pagebreak-numbering.png Binary files differnew file mode 100644 index 00000000..e3a515b7 --- /dev/null +++ b/tests/ref/issue-2095-pagebreak-numbering.png diff --git a/tests/ref/issue-2105-linebreak-tofu.png b/tests/ref/issue-2105-linebreak-tofu.png Binary files differnew file mode 100644 index 00000000..197412b9 --- /dev/null +++ b/tests/ref/issue-2105-linebreak-tofu.png diff --git a/tests/ref/issue-2128-block-width-box.png b/tests/ref/issue-2128-block-width-box.png Binary files differnew file mode 100644 index 00000000..40fe6b4f --- /dev/null +++ b/tests/ref/issue-2128-block-width-box.png diff --git a/tests/ref/issue-2134-pagebreak-bibliography.png b/tests/ref/issue-2134-pagebreak-bibliography.png Binary files differnew file mode 100644 index 00000000..ad0fb165 --- /dev/null +++ b/tests/ref/issue-2134-pagebreak-bibliography.png diff --git a/tests/ref/issue-2162-pagebreak-set-style.png b/tests/ref/issue-2162-pagebreak-set-style.png Binary files differnew file mode 100644 index 00000000..4ea6f56f --- /dev/null +++ b/tests/ref/issue-2162-pagebreak-set-style.png diff --git a/tests/ref/issue-2199-place-spacing-bottom.png b/tests/ref/issue-2199-place-spacing-bottom.png Binary files differnew file mode 100644 index 00000000..1f27559b --- /dev/null +++ b/tests/ref/issue-2199-place-spacing-bottom.png diff --git a/tests/ref/issue-2199-place-spacing-default.png b/tests/ref/issue-2199-place-spacing-default.png Binary files differnew file mode 100644 index 00000000..565a8302 --- /dev/null +++ b/tests/ref/issue-2199-place-spacing-default.png diff --git a/tests/ref/issue-2214-baseline-math.png b/tests/ref/issue-2214-baseline-math.png Binary files differnew file mode 100644 index 00000000..9a3e6f3c --- /dev/null +++ b/tests/ref/issue-2214-baseline-math.png diff --git a/tests/ref/issue-2259-raw-color-overwrite.png b/tests/ref/issue-2259-raw-color-overwrite.png Binary files differnew file mode 100644 index 00000000..9cf42c43 --- /dev/null +++ b/tests/ref/issue-2259-raw-color-overwrite.png diff --git a/tests/ref/issue-2268-mat-augment-color.png b/tests/ref/issue-2268-mat-augment-color.png Binary files differnew file mode 100644 index 00000000..5aca29ca --- /dev/null +++ b/tests/ref/issue-2268-mat-augment-color.png diff --git a/tests/ref/issue-2419-justify-hanging-indent.png b/tests/ref/issue-2419-justify-hanging-indent.png Binary files differnew file mode 100644 index 00000000..bb478ba4 --- /dev/null +++ b/tests/ref/issue-2419-justify-hanging-indent.png diff --git a/tests/ref/issue-2530-enum-item-panic.png b/tests/ref/issue-2530-enum-item-panic.png Binary files differnew file mode 100644 index 00000000..4f6130ba --- /dev/null +++ b/tests/ref/issue-2530-enum-item-panic.png diff --git a/tests/ref/issue-2530-figure-caption-panic.png b/tests/ref/issue-2530-figure-caption-panic.png Binary files differnew file mode 100644 index 00000000..025449ef --- /dev/null +++ b/tests/ref/issue-2530-figure-caption-panic.png diff --git a/tests/ref/issue-2530-list-item-panic.png b/tests/ref/issue-2530-list-item-panic.png Binary files differnew file mode 100644 index 00000000..14d2f570 --- /dev/null +++ b/tests/ref/issue-2530-list-item-panic.png diff --git a/tests/ref/issue-2530-term-item-panic.png b/tests/ref/issue-2530-term-item-panic.png Binary files differnew file mode 100644 index 00000000..85b3e92f --- /dev/null +++ b/tests/ref/issue-2530-term-item-panic.png diff --git a/tests/ref/issue-2531-cite-show-set.png b/tests/ref/issue-2531-cite-show-set.png Binary files differnew file mode 100644 index 00000000..25723f4d --- /dev/null +++ b/tests/ref/issue-2531-cite-show-set.png diff --git a/tests/ref/issue-2538-cjk-latin-spacing-before-linebreak.png b/tests/ref/issue-2538-cjk-latin-spacing-before-linebreak.png Binary files differnew file mode 100644 index 00000000..59571642 --- /dev/null +++ b/tests/ref/issue-2538-cjk-latin-spacing-before-linebreak.png diff --git a/tests/ref/issue-2595-float-overlap.png b/tests/ref/issue-2595-float-overlap.png Binary files differnew file mode 100644 index 00000000..4b460579 --- /dev/null +++ b/tests/ref/issue-2595-float-overlap.png diff --git a/tests/ref/issue-2650-cjk-latin-spacing-meta.png b/tests/ref/issue-2650-cjk-latin-spacing-meta.png Binary files differnew file mode 100644 index 00000000..d346b73f --- /dev/null +++ b/tests/ref/issue-2650-cjk-latin-spacing-meta.png diff --git a/tests/ref/issue-2715-float-order.png b/tests/ref/issue-2715-float-order.png Binary files differnew file mode 100644 index 00000000..01599d25 --- /dev/null +++ b/tests/ref/issue-2715-float-order.png diff --git a/tests/ref/issue-2902-gradient-oklab-panic.png b/tests/ref/issue-2902-gradient-oklab-panic.png Binary files differnew file mode 100644 index 00000000..f8e18f7c --- /dev/null +++ b/tests/ref/issue-2902-gradient-oklab-panic.png diff --git a/tests/ref/issue-2902-gradient-oklch-panic.png b/tests/ref/issue-2902-gradient-oklch-panic.png Binary files differnew file mode 100644 index 00000000..1af7200e --- /dev/null +++ b/tests/ref/issue-2902-gradient-oklch-panic.png diff --git a/tests/ref/issue-3082-chinese-punctuation.png b/tests/ref/issue-3082-chinese-punctuation.png Binary files differnew file mode 100644 index 00000000..642013d0 --- /dev/null +++ b/tests/ref/issue-3082-chinese-punctuation.png diff --git a/tests/ref/issue-3191-raw-indent-shrink.png b/tests/ref/issue-3191-raw-indent-shrink.png Binary files differnew file mode 100644 index 00000000..e7ac73b7 --- /dev/null +++ b/tests/ref/issue-3191-raw-indent-shrink.png diff --git a/tests/ref/issue-3191-raw-normal-paragraphs-still-shrink.png b/tests/ref/issue-3191-raw-normal-paragraphs-still-shrink.png Binary files differnew file mode 100644 index 00000000..1eb49995 --- /dev/null +++ b/tests/ref/issue-3191-raw-normal-paragraphs-still-shrink.png diff --git a/tests/ref/issue-3232-dict-empty.png b/tests/ref/issue-3232-dict-empty.png Binary files differnew file mode 100644 index 00000000..f8d3f324 --- /dev/null +++ b/tests/ref/issue-3232-dict-empty.png diff --git a/tests/ref/issue-3264-rect-negative-dimensions.png b/tests/ref/issue-3264-rect-negative-dimensions.png Binary files differnew file mode 100644 index 00000000..44a04681 --- /dev/null +++ b/tests/ref/issue-3264-rect-negative-dimensions.png diff --git a/tests/ref/issue-3363-json-large-number.png b/tests/ref/issue-3363-json-large-number.png Binary files differnew file mode 100644 index 00000000..3e13dea1 --- /dev/null +++ b/tests/ref/issue-3363-json-large-number.png diff --git a/tests/ref/issue-3586-figure-caption-separator.png b/tests/ref/issue-3586-figure-caption-separator.png Binary files differnew file mode 100644 index 00000000..1d038fe3 --- /dev/null +++ b/tests/ref/issue-3586-figure-caption-separator.png diff --git a/tests/ref/issue-3624-spacing-behaviour.png b/tests/ref/issue-3624-spacing-behaviour.png Binary files differnew file mode 100644 index 00000000..c7db6753 --- /dev/null +++ b/tests/ref/issue-3624-spacing-behaviour.png diff --git a/tests/ref/issue-3641-float-loop.png b/tests/ref/issue-3641-float-loop.png Binary files differnew file mode 100644 index 00000000..4490d30a --- /dev/null +++ b/tests/ref/issue-3641-float-loop.png diff --git a/tests/ref/issue-3650-italic-equation.png b/tests/ref/issue-3650-italic-equation.png Binary files differnew file mode 100644 index 00000000..484457e8 --- /dev/null +++ b/tests/ref/issue-3650-italic-equation.png diff --git a/tests/ref/issue-3658-math-size.png b/tests/ref/issue-3658-math-size.png Binary files differnew file mode 100644 index 00000000..db8fccf9 --- /dev/null +++ b/tests/ref/issue-3658-math-size.png diff --git a/tests/ref/issue-3662-pdf-smartquotes.png b/tests/ref/issue-3662-pdf-smartquotes.png Binary files differnew file mode 100644 index 00000000..ff73cbc8 --- /dev/null +++ b/tests/ref/issue-3662-pdf-smartquotes.png diff --git a/tests/ref/issue-3700-deformed-stroke.png b/tests/ref/issue-3700-deformed-stroke.png Binary files differnew file mode 100644 index 00000000..9578a675 --- /dev/null +++ b/tests/ref/issue-3700-deformed-stroke.png diff --git a/tests/ref/issue-3841-tabs-in-raw-type-code.png b/tests/ref/issue-3841-tabs-in-raw-type-code.png Binary files differnew file mode 100644 index 00000000..b7a7b1ba --- /dev/null +++ b/tests/ref/issue-3841-tabs-in-raw-type-code.png diff --git a/tests/ref/issue-622-hide-meta-cite.png b/tests/ref/issue-622-hide-meta-cite.png Binary files differnew file mode 100644 index 00000000..8918f668 --- /dev/null +++ b/tests/ref/issue-622-hide-meta-cite.png diff --git a/tests/ref/issue-622-hide-meta-outline.png b/tests/ref/issue-622-hide-meta-outline.png Binary files differnew file mode 100644 index 00000000..72a82e4d --- /dev/null +++ b/tests/ref/issue-622-hide-meta-outline.png diff --git a/tests/ref/issue-785-cite-locate.png b/tests/ref/issue-785-cite-locate.png Binary files differnew file mode 100644 index 00000000..7c2a650a --- /dev/null +++ b/tests/ref/issue-785-cite-locate.png diff --git a/tests/ref/issue-80-emoji-linebreak.png b/tests/ref/issue-80-emoji-linebreak.png Binary files differnew file mode 100644 index 00000000..d35a62b3 --- /dev/null +++ b/tests/ref/issue-80-emoji-linebreak.png diff --git a/tests/ref/issue-852-mat-type.png b/tests/ref/issue-852-mat-type.png Binary files differnew file mode 100644 index 00000000..81af3bb5 --- /dev/null +++ b/tests/ref/issue-852-mat-type.png diff --git a/tests/ref/issue-870-image-rotation.png b/tests/ref/issue-870-image-rotation.png Binary files differnew file mode 100644 index 00000000..c321a1a9 --- /dev/null +++ b/tests/ref/issue-870-image-rotation.png diff --git a/tests/ref/issue-886-args-sink.png b/tests/ref/issue-886-args-sink.png Binary files differnew file mode 100644 index 00000000..2ef08adf --- /dev/null +++ b/tests/ref/issue-886-args-sink.png diff --git a/tests/ref/issue-columns-heading.png b/tests/ref/issue-columns-heading.png Binary files differnew file mode 100644 index 00000000..700972bc --- /dev/null +++ b/tests/ref/issue-columns-heading.png diff --git a/tests/ref/issue-flow-frame-placement.png b/tests/ref/issue-flow-frame-placement.png Binary files differnew file mode 100644 index 00000000..27469c27 --- /dev/null +++ b/tests/ref/issue-flow-frame-placement.png diff --git a/tests/ref/issue-flow-layout-index-out-of-bounds.png b/tests/ref/issue-flow-layout-index-out-of-bounds.png Binary files differnew file mode 100644 index 00000000..8746cbfc --- /dev/null +++ b/tests/ref/issue-flow-layout-index-out-of-bounds.png diff --git a/tests/ref/issue-flow-overlarge-frames.png b/tests/ref/issue-flow-overlarge-frames.png Binary files differnew file mode 100644 index 00000000..016af525 --- /dev/null +++ b/tests/ref/issue-flow-overlarge-frames.png diff --git a/tests/ref/issue-flow-trailing-leading.png b/tests/ref/issue-flow-trailing-leading.png Binary files differnew file mode 100644 index 00000000..4245d42f --- /dev/null +++ b/tests/ref/issue-flow-trailing-leading.png diff --git a/tests/ref/issue-flow-weak-spacing.png b/tests/ref/issue-flow-weak-spacing.png Binary files differnew file mode 100644 index 00000000..e37a5ae3 --- /dev/null +++ b/tests/ref/issue-flow-weak-spacing.png diff --git a/tests/ref/issue-gradient-cmyk-encode.png b/tests/ref/issue-gradient-cmyk-encode.png Binary files differnew file mode 100644 index 00000000..065d1a3b --- /dev/null +++ b/tests/ref/issue-gradient-cmyk-encode.png diff --git a/tests/ref/issue-grid-base-auto-row-list.png b/tests/ref/issue-grid-base-auto-row-list.png Binary files differnew file mode 100644 index 00000000..8da3adf5 --- /dev/null +++ b/tests/ref/issue-grid-base-auto-row-list.png diff --git a/tests/ref/issue-grid-base-auto-row.png b/tests/ref/issue-grid-base-auto-row.png Binary files differnew file mode 100644 index 00000000..0e05577d --- /dev/null +++ b/tests/ref/issue-grid-base-auto-row.png diff --git a/tests/ref/issue-grid-double-skip.png b/tests/ref/issue-grid-double-skip.png Binary files differnew file mode 100644 index 00000000..2901f29a --- /dev/null +++ b/tests/ref/issue-grid-double-skip.png diff --git a/tests/ref/issue-grid-gutter-skip.png b/tests/ref/issue-grid-gutter-skip.png Binary files differnew file mode 100644 index 00000000..3404fd10 --- /dev/null +++ b/tests/ref/issue-grid-gutter-skip.png diff --git a/tests/ref/issue-grid-skip-list.png b/tests/ref/issue-grid-skip-list.png Binary files differnew file mode 100644 index 00000000..bd674337 --- /dev/null +++ b/tests/ref/issue-grid-skip-list.png diff --git a/tests/ref/issue-grid-skip.png b/tests/ref/issue-grid-skip.png Binary files differnew file mode 100644 index 00000000..1b46fd1a --- /dev/null +++ b/tests/ref/issue-grid-skip.png diff --git a/tests/ref/issue-math-realize-hide.png b/tests/ref/issue-math-realize-hide.png Binary files differnew file mode 100644 index 00000000..729e9f00 --- /dev/null +++ b/tests/ref/issue-math-realize-hide.png diff --git a/tests/ref/issue-math-realize-scripting.png b/tests/ref/issue-math-realize-scripting.png Binary files differnew file mode 100644 index 00000000..a29b0364 --- /dev/null +++ b/tests/ref/issue-math-realize-scripting.png diff --git a/tests/ref/issue-math-realize-show.png b/tests/ref/issue-math-realize-show.png Binary files differnew file mode 100644 index 00000000..d6b727c1 --- /dev/null +++ b/tests/ref/issue-math-realize-show.png diff --git a/tests/ref/issue-multiple-footnote-in-one-line.png b/tests/ref/issue-multiple-footnote-in-one-line.png Binary files differnew file mode 100644 index 00000000..1d8c017d --- /dev/null +++ b/tests/ref/issue-multiple-footnote-in-one-line.png diff --git a/tests/ref/issue-non-atomic-closure.png b/tests/ref/issue-non-atomic-closure.png Binary files differnew file mode 100644 index 00000000..f60b4654 --- /dev/null +++ b/tests/ref/issue-non-atomic-closure.png diff --git a/tests/ref/issue-place-base.png b/tests/ref/issue-place-base.png Binary files differnew file mode 100644 index 00000000..45517fe9 --- /dev/null +++ b/tests/ref/issue-place-base.png diff --git a/tests/ref/issue-rtl-safe-to-break-panic.png b/tests/ref/issue-rtl-safe-to-break-panic.png Binary files differnew file mode 100644 index 00000000..5cd9920c --- /dev/null +++ b/tests/ref/issue-rtl-safe-to-break-panic.png diff --git a/tests/ref/justify-avoid-runts.png b/tests/ref/justify-avoid-runts.png Binary files differnew file mode 100644 index 00000000..70513939 --- /dev/null +++ b/tests/ref/justify-avoid-runts.png diff --git a/tests/ref/justify-chinese.png b/tests/ref/justify-chinese.png Binary files differnew file mode 100644 index 00000000..0284e8b9 --- /dev/null +++ b/tests/ref/justify-chinese.png diff --git a/tests/ref/justify-code-blocks.png b/tests/ref/justify-code-blocks.png Binary files differnew file mode 100644 index 00000000..088e8b63 --- /dev/null +++ b/tests/ref/justify-code-blocks.png diff --git a/tests/ref/justify-japanese.png b/tests/ref/justify-japanese.png Binary files differnew file mode 100644 index 00000000..addeba54 --- /dev/null +++ b/tests/ref/justify-japanese.png diff --git a/tests/ref/justify-justified-linebreak.png b/tests/ref/justify-justified-linebreak.png Binary files differnew file mode 100644 index 00000000..8792e9e2 --- /dev/null +++ b/tests/ref/justify-justified-linebreak.png diff --git a/tests/ref/justify-knuth-story.png b/tests/ref/justify-knuth-story.png Binary files differnew file mode 100644 index 00000000..9fbcc3c3 --- /dev/null +++ b/tests/ref/justify-knuth-story.png diff --git a/tests/ref/justify-manual-linebreak.png b/tests/ref/justify-manual-linebreak.png Binary files differnew file mode 100644 index 00000000..144a62c7 --- /dev/null +++ b/tests/ref/justify-manual-linebreak.png diff --git a/tests/ref/justify-no-leading-spaces.png b/tests/ref/justify-no-leading-spaces.png Binary files differnew file mode 100644 index 00000000..9d2557b5 --- /dev/null +++ b/tests/ref/justify-no-leading-spaces.png diff --git a/tests/ref/justify-punctuation-adjustment.png b/tests/ref/justify-punctuation-adjustment.png Binary files differnew file mode 100644 index 00000000..28d4ef04 --- /dev/null +++ b/tests/ref/justify-punctuation-adjustment.png diff --git a/tests/ref/justify-shrink-last-line.png b/tests/ref/justify-shrink-last-line.png Binary files differnew file mode 100644 index 00000000..f839e92e --- /dev/null +++ b/tests/ref/justify-shrink-last-line.png diff --git a/tests/ref/justify-variants.png b/tests/ref/justify-variants.png Binary files differnew file mode 100644 index 00000000..81fcc700 --- /dev/null +++ b/tests/ref/justify-variants.png diff --git a/tests/ref/justify-whitespace-adjustment.png b/tests/ref/justify-whitespace-adjustment.png Binary files differnew file mode 100644 index 00000000..4ea6829c --- /dev/null +++ b/tests/ref/justify-whitespace-adjustment.png diff --git a/tests/ref/justify-without-justifiables.png b/tests/ref/justify-without-justifiables.png Binary files differnew file mode 100644 index 00000000..77e5bf1b --- /dev/null +++ b/tests/ref/justify-without-justifiables.png diff --git a/tests/ref/justify.png b/tests/ref/justify.png Binary files differnew file mode 100644 index 00000000..4e4fdbf5 --- /dev/null +++ b/tests/ref/justify.png diff --git a/tests/ref/label-after-expression.png b/tests/ref/label-after-expression.png Binary files differnew file mode 100644 index 00000000..5ceaf342 --- /dev/null +++ b/tests/ref/label-after-expression.png diff --git a/tests/ref/label-after-parbreak.png b/tests/ref/label-after-parbreak.png Binary files differnew file mode 100644 index 00000000..9339c65c --- /dev/null +++ b/tests/ref/label-after-parbreak.png diff --git a/tests/ref/label-dynamic-show-set.png b/tests/ref/label-dynamic-show-set.png Binary files differnew file mode 100644 index 00000000..25681b92 --- /dev/null +++ b/tests/ref/label-dynamic-show-set.png diff --git a/tests/ref/label-in-block.png b/tests/ref/label-in-block.png Binary files differnew file mode 100644 index 00000000..e97bd725 --- /dev/null +++ b/tests/ref/label-in-block.png diff --git a/tests/ref/label-on-text.png b/tests/ref/label-on-text.png Binary files differnew file mode 100644 index 00000000..67fb1aa8 --- /dev/null +++ b/tests/ref/label-on-text.png diff --git a/tests/ref/label-show-where-selector.png b/tests/ref/label-show-where-selector.png Binary files differnew file mode 100644 index 00000000..61e90a9a --- /dev/null +++ b/tests/ref/label-show-where-selector.png diff --git a/tests/ref/label-unclosed-is-text.png b/tests/ref/label-unclosed-is-text.png Binary files differnew file mode 100644 index 00000000..051db0cf --- /dev/null +++ b/tests/ref/label-unclosed-is-text.png diff --git a/tests/ref/layout-in-fixed-size-block.png b/tests/ref/layout-in-fixed-size-block.png Binary files differnew file mode 100644 index 00000000..6cc321b3 --- /dev/null +++ b/tests/ref/layout-in-fixed-size-block.png diff --git a/tests/ref/layout-in-page-call.png b/tests/ref/layout-in-page-call.png Binary files differnew file mode 100644 index 00000000..9bc75ae7 --- /dev/null +++ b/tests/ref/layout-in-page-call.png diff --git a/tests/ref/layout/align.png b/tests/ref/layout/align.png Binary files differdeleted file mode 100644 index a0113597..00000000 --- a/tests/ref/layout/align.png +++ /dev/null diff --git a/tests/ref/layout/block-sizing.png b/tests/ref/layout/block-sizing.png Binary files differdeleted file mode 100644 index 7d57a0d8..00000000 --- a/tests/ref/layout/block-sizing.png +++ /dev/null diff --git a/tests/ref/layout/block-spacing.png b/tests/ref/layout/block-spacing.png Binary files differdeleted file mode 100644 index d73abac0..00000000 --- a/tests/ref/layout/block-spacing.png +++ /dev/null diff --git a/tests/ref/layout/cjk-latin-spacing.png b/tests/ref/layout/cjk-latin-spacing.png Binary files differdeleted file mode 100644 index 629145e4..00000000 --- a/tests/ref/layout/cjk-latin-spacing.png +++ /dev/null diff --git a/tests/ref/layout/cjk-punctuation-adjustment.png b/tests/ref/layout/cjk-punctuation-adjustment.png Binary files differdeleted file mode 100644 index 1da08f23..00000000 --- a/tests/ref/layout/cjk-punctuation-adjustment.png +++ /dev/null diff --git a/tests/ref/layout/clip.png b/tests/ref/layout/clip.png Binary files differdeleted file mode 100644 index f37bf9ad..00000000 --- a/tests/ref/layout/clip.png +++ /dev/null diff --git a/tests/ref/layout/code-indent-shrink.png b/tests/ref/layout/code-indent-shrink.png Binary files differdeleted file mode 100644 index 26f6ec40..00000000 --- a/tests/ref/layout/code-indent-shrink.png +++ /dev/null diff --git a/tests/ref/layout/columns.png b/tests/ref/layout/columns.png Binary files differdeleted file mode 100644 index 38912f1b..00000000 --- a/tests/ref/layout/columns.png +++ /dev/null diff --git a/tests/ref/layout/container-fill.png b/tests/ref/layout/container-fill.png Binary files differdeleted file mode 100644 index 74fdc73d..00000000 --- a/tests/ref/layout/container-fill.png +++ /dev/null diff --git a/tests/ref/layout/container.png b/tests/ref/layout/container.png Binary files differdeleted file mode 100644 index 0cd56b2d..00000000 --- a/tests/ref/layout/container.png +++ /dev/null diff --git a/tests/ref/layout/enum-align.png b/tests/ref/layout/enum-align.png Binary files differdeleted file mode 100644 index 18e392f2..00000000 --- a/tests/ref/layout/enum-align.png +++ /dev/null diff --git a/tests/ref/layout/enum-numbering.png b/tests/ref/layout/enum-numbering.png Binary files differdeleted file mode 100644 index e1b2103b..00000000 --- a/tests/ref/layout/enum-numbering.png +++ /dev/null diff --git a/tests/ref/layout/enum.png b/tests/ref/layout/enum.png Binary files differdeleted file mode 100644 index 62f1e4ab..00000000 --- a/tests/ref/layout/enum.png +++ /dev/null diff --git a/tests/ref/layout/flow-orphan.png b/tests/ref/layout/flow-orphan.png Binary files differdeleted file mode 100644 index 434636c4..00000000 --- a/tests/ref/layout/flow-orphan.png +++ /dev/null diff --git a/tests/ref/layout/grid-1.png b/tests/ref/layout/grid-1.png Binary files differdeleted file mode 100644 index 9e33772c..00000000 --- a/tests/ref/layout/grid-1.png +++ /dev/null diff --git a/tests/ref/layout/grid-2.png b/tests/ref/layout/grid-2.png Binary files differdeleted file mode 100644 index ac1f7014..00000000 --- a/tests/ref/layout/grid-2.png +++ /dev/null diff --git a/tests/ref/layout/grid-3.png b/tests/ref/layout/grid-3.png Binary files differdeleted file mode 100644 index 0f54f2cc..00000000 --- a/tests/ref/layout/grid-3.png +++ /dev/null diff --git a/tests/ref/layout/grid-4.png b/tests/ref/layout/grid-4.png Binary files differdeleted file mode 100644 index 35a05ab5..00000000 --- a/tests/ref/layout/grid-4.png +++ /dev/null diff --git a/tests/ref/layout/grid-5.png b/tests/ref/layout/grid-5.png Binary files differdeleted file mode 100644 index 233ebb00..00000000 --- a/tests/ref/layout/grid-5.png +++ /dev/null diff --git a/tests/ref/layout/grid-auto-shrink.png b/tests/ref/layout/grid-auto-shrink.png Binary files differdeleted file mode 100644 index 34995215..00000000 --- a/tests/ref/layout/grid-auto-shrink.png +++ /dev/null diff --git a/tests/ref/layout/grid-cell.png b/tests/ref/layout/grid-cell.png Binary files differdeleted file mode 100644 index 07508b40..00000000 --- a/tests/ref/layout/grid-cell.png +++ /dev/null diff --git a/tests/ref/layout/grid-colspan.png b/tests/ref/layout/grid-colspan.png Binary files differdeleted file mode 100644 index e16ca347..00000000 --- a/tests/ref/layout/grid-colspan.png +++ /dev/null diff --git a/tests/ref/layout/grid-footers-1.png b/tests/ref/layout/grid-footers-1.png Binary files differdeleted file mode 100644 index 331cf7ad..00000000 --- a/tests/ref/layout/grid-footers-1.png +++ /dev/null diff --git a/tests/ref/layout/grid-footers-2.png b/tests/ref/layout/grid-footers-2.png Binary files differdeleted file mode 100644 index 60e9689c..00000000 --- a/tests/ref/layout/grid-footers-2.png +++ /dev/null diff --git a/tests/ref/layout/grid-footers-3.png b/tests/ref/layout/grid-footers-3.png Binary files differdeleted file mode 100644 index cc4948b8..00000000 --- a/tests/ref/layout/grid-footers-3.png +++ /dev/null diff --git a/tests/ref/layout/grid-footers-4.png b/tests/ref/layout/grid-footers-4.png Binary files differdeleted file mode 100644 index 29a6430b..00000000 --- a/tests/ref/layout/grid-footers-4.png +++ /dev/null diff --git a/tests/ref/layout/grid-footers-5.png b/tests/ref/layout/grid-footers-5.png Binary files differdeleted file mode 100644 index 6cae5592..00000000 --- a/tests/ref/layout/grid-footers-5.png +++ /dev/null diff --git a/tests/ref/layout/grid-headers-1.png b/tests/ref/layout/grid-headers-1.png Binary files differdeleted file mode 100644 index 7ae2d8d3..00000000 --- a/tests/ref/layout/grid-headers-1.png +++ /dev/null diff --git a/tests/ref/layout/grid-headers-2.png b/tests/ref/layout/grid-headers-2.png Binary files differdeleted file mode 100644 index 3dbc07c8..00000000 --- a/tests/ref/layout/grid-headers-2.png +++ /dev/null diff --git a/tests/ref/layout/grid-headers-3.png b/tests/ref/layout/grid-headers-3.png Binary files differdeleted file mode 100644 index 9ee77d50..00000000 --- a/tests/ref/layout/grid-headers-3.png +++ /dev/null diff --git a/tests/ref/layout/grid-headers-4.png b/tests/ref/layout/grid-headers-4.png Binary files differdeleted file mode 100644 index 1f3e4b10..00000000 --- a/tests/ref/layout/grid-headers-4.png +++ /dev/null diff --git a/tests/ref/layout/grid-positioning.png b/tests/ref/layout/grid-positioning.png Binary files differdeleted file mode 100644 index cac93f40..00000000 --- a/tests/ref/layout/grid-positioning.png +++ /dev/null diff --git a/tests/ref/layout/grid-rowspan-basic.png b/tests/ref/layout/grid-rowspan-basic.png Binary files differdeleted file mode 100644 index b464d8b4..00000000 --- a/tests/ref/layout/grid-rowspan-basic.png +++ /dev/null diff --git a/tests/ref/layout/grid-rowspan-split-1.png b/tests/ref/layout/grid-rowspan-split-1.png Binary files differdeleted file mode 100644 index 12cd5fc6..00000000 --- a/tests/ref/layout/grid-rowspan-split-1.png +++ /dev/null diff --git a/tests/ref/layout/grid-rowspan-split-2.png b/tests/ref/layout/grid-rowspan-split-2.png Binary files differdeleted file mode 100644 index e55c5e23..00000000 --- a/tests/ref/layout/grid-rowspan-split-2.png +++ /dev/null diff --git a/tests/ref/layout/grid-rowspan-split-3.png b/tests/ref/layout/grid-rowspan-split-3.png Binary files differdeleted file mode 100644 index c3ff4bd1..00000000 --- a/tests/ref/layout/grid-rowspan-split-3.png +++ /dev/null diff --git a/tests/ref/layout/grid-rtl.png b/tests/ref/layout/grid-rtl.png Binary files differdeleted file mode 100644 index d628ee8a..00000000 --- a/tests/ref/layout/grid-rtl.png +++ /dev/null diff --git a/tests/ref/layout/grid-stroke.png b/tests/ref/layout/grid-stroke.png Binary files differdeleted file mode 100644 index fbba379e..00000000 --- a/tests/ref/layout/grid-stroke.png +++ /dev/null diff --git a/tests/ref/layout/grid-styling.png b/tests/ref/layout/grid-styling.png Binary files differdeleted file mode 100644 index dc50dd90..00000000 --- a/tests/ref/layout/grid-styling.png +++ /dev/null diff --git a/tests/ref/layout/hide.png b/tests/ref/layout/hide.png Binary files differdeleted file mode 100644 index d8980049..00000000 --- a/tests/ref/layout/hide.png +++ /dev/null diff --git a/tests/ref/layout/list-attach.png b/tests/ref/layout/list-attach.png Binary files differdeleted file mode 100644 index 4a6a4573..00000000 --- a/tests/ref/layout/list-attach.png +++ /dev/null diff --git a/tests/ref/layout/list-marker.png b/tests/ref/layout/list-marker.png Binary files differdeleted file mode 100644 index 19d6ed5f..00000000 --- a/tests/ref/layout/list-marker.png +++ /dev/null diff --git a/tests/ref/layout/list.png b/tests/ref/layout/list.png Binary files differdeleted file mode 100644 index 269243eb..00000000 --- a/tests/ref/layout/list.png +++ /dev/null diff --git a/tests/ref/layout/out-of-flow-in-block.png b/tests/ref/layout/out-of-flow-in-block.png Binary files differdeleted file mode 100644 index 97637145..00000000 --- a/tests/ref/layout/out-of-flow-in-block.png +++ /dev/null diff --git a/tests/ref/layout/pad.png b/tests/ref/layout/pad.png Binary files differdeleted file mode 100644 index d228f07f..00000000 --- a/tests/ref/layout/pad.png +++ /dev/null diff --git a/tests/ref/layout/page-binding.png b/tests/ref/layout/page-binding.png Binary files differdeleted file mode 100644 index 5b6d0657..00000000 --- a/tests/ref/layout/page-binding.png +++ /dev/null diff --git a/tests/ref/layout/page-margin.png b/tests/ref/layout/page-margin.png Binary files differdeleted file mode 100644 index f690724b..00000000 --- a/tests/ref/layout/page-margin.png +++ /dev/null diff --git a/tests/ref/layout/page-marginals.png b/tests/ref/layout/page-marginals.png Binary files differdeleted file mode 100644 index bbe6358e..00000000 --- a/tests/ref/layout/page-marginals.png +++ /dev/null diff --git a/tests/ref/layout/page-number-align.png b/tests/ref/layout/page-number-align.png Binary files differdeleted file mode 100644 index b05ca454..00000000 --- a/tests/ref/layout/page-number-align.png +++ /dev/null diff --git a/tests/ref/layout/page-style.png b/tests/ref/layout/page-style.png Binary files differdeleted file mode 100644 index ac6b602c..00000000 --- a/tests/ref/layout/page-style.png +++ /dev/null diff --git a/tests/ref/layout/page.png b/tests/ref/layout/page.png Binary files differdeleted file mode 100644 index bcf32526..00000000 --- a/tests/ref/layout/page.png +++ /dev/null diff --git a/tests/ref/layout/pagebreak-parity.png b/tests/ref/layout/pagebreak-parity.png Binary files differdeleted file mode 100644 index 0dbabe7a..00000000 --- a/tests/ref/layout/pagebreak-parity.png +++ /dev/null diff --git a/tests/ref/layout/pagebreak-weak.png b/tests/ref/layout/pagebreak-weak.png Binary files differdeleted file mode 100644 index 412c4e8d..00000000 --- a/tests/ref/layout/pagebreak-weak.png +++ /dev/null diff --git a/tests/ref/layout/pagebreak.png b/tests/ref/layout/pagebreak.png Binary files differdeleted file mode 100644 index ab055643..00000000 --- a/tests/ref/layout/pagebreak.png +++ /dev/null diff --git a/tests/ref/layout/par-bidi.png b/tests/ref/layout/par-bidi.png Binary files differdeleted file mode 100644 index af66a719..00000000 --- a/tests/ref/layout/par-bidi.png +++ /dev/null diff --git a/tests/ref/layout/par-indent.png b/tests/ref/layout/par-indent.png Binary files differdeleted file mode 100644 index cceaa3b9..00000000 --- a/tests/ref/layout/par-indent.png +++ /dev/null diff --git a/tests/ref/layout/par-justify-cjk.png b/tests/ref/layout/par-justify-cjk.png Binary files differdeleted file mode 100644 index 25adfcb2..00000000 --- a/tests/ref/layout/par-justify-cjk.png +++ /dev/null diff --git a/tests/ref/layout/par-justify.png b/tests/ref/layout/par-justify.png Binary files differdeleted file mode 100644 index 0cd9cbcd..00000000 --- a/tests/ref/layout/par-justify.png +++ /dev/null diff --git a/tests/ref/layout/par-knuth.png b/tests/ref/layout/par-knuth.png Binary files differdeleted file mode 100644 index f3da1753..00000000 --- a/tests/ref/layout/par-knuth.png +++ /dev/null diff --git a/tests/ref/layout/par-simple.png b/tests/ref/layout/par-simple.png Binary files differdeleted file mode 100644 index a645bfd8..00000000 --- a/tests/ref/layout/par-simple.png +++ /dev/null diff --git a/tests/ref/layout/par.png b/tests/ref/layout/par.png Binary files differdeleted file mode 100644 index f25f56d2..00000000 --- a/tests/ref/layout/par.png +++ /dev/null diff --git a/tests/ref/layout/place-background.png b/tests/ref/layout/place-background.png Binary files differdeleted file mode 100644 index d9c1c42f..00000000 --- a/tests/ref/layout/place-background.png +++ /dev/null diff --git a/tests/ref/layout/place-float-auto.png b/tests/ref/layout/place-float-auto.png Binary files differdeleted file mode 100644 index f2e4ee92..00000000 --- a/tests/ref/layout/place-float-auto.png +++ /dev/null diff --git a/tests/ref/layout/place-float-columns.png b/tests/ref/layout/place-float-columns.png Binary files differdeleted file mode 100644 index 186b79d1..00000000 --- a/tests/ref/layout/place-float-columns.png +++ /dev/null diff --git a/tests/ref/layout/place-float-figure.png b/tests/ref/layout/place-float-figure.png Binary files differdeleted file mode 100644 index bf9d21b4..00000000 --- a/tests/ref/layout/place-float-figure.png +++ /dev/null diff --git a/tests/ref/layout/place-nested.png b/tests/ref/layout/place-nested.png Binary files differdeleted file mode 100644 index 864830d8..00000000 --- a/tests/ref/layout/place-nested.png +++ /dev/null diff --git a/tests/ref/layout/place.png b/tests/ref/layout/place.png Binary files differdeleted file mode 100644 index 2ef85a4d..00000000 --- a/tests/ref/layout/place.png +++ /dev/null diff --git a/tests/ref/layout/repeat.png b/tests/ref/layout/repeat.png Binary files differdeleted file mode 100644 index 8e21f102..00000000 --- a/tests/ref/layout/repeat.png +++ /dev/null diff --git a/tests/ref/layout/spacing.png b/tests/ref/layout/spacing.png Binary files differdeleted file mode 100644 index 9bab536a..00000000 --- a/tests/ref/layout/spacing.png +++ /dev/null diff --git a/tests/ref/layout/stack-1.png b/tests/ref/layout/stack-1.png Binary files differdeleted file mode 100644 index 1a3133b8..00000000 --- a/tests/ref/layout/stack-1.png +++ /dev/null diff --git a/tests/ref/layout/stack-2.png b/tests/ref/layout/stack-2.png Binary files differdeleted file mode 100644 index 6cb0aad2..00000000 --- a/tests/ref/layout/stack-2.png +++ /dev/null diff --git a/tests/ref/layout/table-cell.png b/tests/ref/layout/table-cell.png Binary files differdeleted file mode 100644 index 647a2e10..00000000 --- a/tests/ref/layout/table-cell.png +++ /dev/null diff --git a/tests/ref/layout/table.png b/tests/ref/layout/table.png Binary files differdeleted file mode 100644 index ddd0e043..00000000 --- a/tests/ref/layout/table.png +++ /dev/null diff --git a/tests/ref/layout/terms.png b/tests/ref/layout/terms.png Binary files differdeleted file mode 100644 index e0cd013a..00000000 --- a/tests/ref/layout/terms.png +++ /dev/null diff --git a/tests/ref/layout/transform-layout.png b/tests/ref/layout/transform-layout.png Binary files differdeleted file mode 100644 index 576824f0..00000000 --- a/tests/ref/layout/transform-layout.png +++ /dev/null diff --git a/tests/ref/layout/transform.png b/tests/ref/layout/transform.png Binary files differdeleted file mode 100644 index 83b7d13a..00000000 --- a/tests/ref/layout/transform.png +++ /dev/null diff --git a/tests/ref/let-basic.png b/tests/ref/let-basic.png Binary files differnew file mode 100644 index 00000000..ded47a5a --- /dev/null +++ b/tests/ref/let-basic.png diff --git a/tests/ref/let-termination.png b/tests/ref/let-termination.png Binary files differnew file mode 100644 index 00000000..552bb4ce --- /dev/null +++ b/tests/ref/let-termination.png diff --git a/tests/ref/line-basic.png b/tests/ref/line-basic.png Binary files differnew file mode 100644 index 00000000..007672e1 --- /dev/null +++ b/tests/ref/line-basic.png diff --git a/tests/ref/line-positioning.png b/tests/ref/line-positioning.png Binary files differnew file mode 100644 index 00000000..65678caa --- /dev/null +++ b/tests/ref/line-positioning.png diff --git a/tests/ref/line-stroke-dash.png b/tests/ref/line-stroke-dash.png Binary files differnew file mode 100644 index 00000000..f245e32f --- /dev/null +++ b/tests/ref/line-stroke-dash.png diff --git a/tests/ref/line-stroke-set.png b/tests/ref/line-stroke-set.png Binary files differnew file mode 100644 index 00000000..f82f899e --- /dev/null +++ b/tests/ref/line-stroke-set.png diff --git a/tests/ref/line-stroke.png b/tests/ref/line-stroke.png Binary files differnew file mode 100644 index 00000000..d0213002 --- /dev/null +++ b/tests/ref/line-stroke.png diff --git a/tests/ref/linebreak-cite-punctuation.png b/tests/ref/linebreak-cite-punctuation.png Binary files differnew file mode 100644 index 00000000..64d930c6 --- /dev/null +++ b/tests/ref/linebreak-cite-punctuation.png diff --git a/tests/ref/linebreak-hyphen-nbsp.png b/tests/ref/linebreak-hyphen-nbsp.png Binary files differnew file mode 100644 index 00000000..ee88ae58 --- /dev/null +++ b/tests/ref/linebreak-hyphen-nbsp.png diff --git a/tests/ref/linebreak-link-end.png b/tests/ref/linebreak-link-end.png Binary files differnew file mode 100644 index 00000000..f11e91d6 --- /dev/null +++ b/tests/ref/linebreak-link-end.png diff --git a/tests/ref/linebreak-link-justify.png b/tests/ref/linebreak-link-justify.png Binary files differnew file mode 100644 index 00000000..8007cf3e --- /dev/null +++ b/tests/ref/linebreak-link-justify.png diff --git a/tests/ref/linebreak-link.png b/tests/ref/linebreak-link.png Binary files differnew file mode 100644 index 00000000..d5ba8c9e --- /dev/null +++ b/tests/ref/linebreak-link.png diff --git a/tests/ref/linebreak-manual-consecutive.png b/tests/ref/linebreak-manual-consecutive.png Binary files differnew file mode 100644 index 00000000..0dbef35b --- /dev/null +++ b/tests/ref/linebreak-manual-consecutive.png diff --git a/tests/ref/linebreak-manual-directly-after-automatic.png b/tests/ref/linebreak-manual-directly-after-automatic.png Binary files differnew file mode 100644 index 00000000..006e3ef2 --- /dev/null +++ b/tests/ref/linebreak-manual-directly-after-automatic.png diff --git a/tests/ref/linebreak-manual-justified.png b/tests/ref/linebreak-manual-justified.png Binary files differnew file mode 100644 index 00000000..f74ea3fd --- /dev/null +++ b/tests/ref/linebreak-manual-justified.png diff --git a/tests/ref/linebreak-manual-trailing-multiple.png b/tests/ref/linebreak-manual-trailing-multiple.png Binary files differnew file mode 100644 index 00000000..edf3a949 --- /dev/null +++ b/tests/ref/linebreak-manual-trailing-multiple.png diff --git a/tests/ref/linebreak-manual.png b/tests/ref/linebreak-manual.png Binary files differnew file mode 100644 index 00000000..37aca398 --- /dev/null +++ b/tests/ref/linebreak-manual.png diff --git a/tests/ref/linebreak-math-punctuation.png b/tests/ref/linebreak-math-punctuation.png Binary files differnew file mode 100644 index 00000000..93b77d2a --- /dev/null +++ b/tests/ref/linebreak-math-punctuation.png diff --git a/tests/ref/linebreak-narrow-nbsp.png b/tests/ref/linebreak-narrow-nbsp.png Binary files differnew file mode 100644 index 00000000..81cf82f8 --- /dev/null +++ b/tests/ref/linebreak-narrow-nbsp.png diff --git a/tests/ref/linebreak-overflow-double.png b/tests/ref/linebreak-overflow-double.png Binary files differnew file mode 100644 index 00000000..04a5bbaa --- /dev/null +++ b/tests/ref/linebreak-overflow-double.png diff --git a/tests/ref/linebreak-overflow.png b/tests/ref/linebreak-overflow.png Binary files differnew file mode 100644 index 00000000..1dfcbc27 --- /dev/null +++ b/tests/ref/linebreak-overflow.png diff --git a/tests/ref/linebreak-shape-run.png b/tests/ref/linebreak-shape-run.png Binary files differnew file mode 100644 index 00000000..ebfb87f0 --- /dev/null +++ b/tests/ref/linebreak-shape-run.png diff --git a/tests/ref/linebreak-thai.png b/tests/ref/linebreak-thai.png Binary files differnew file mode 100644 index 00000000..8053a212 --- /dev/null +++ b/tests/ref/linebreak-thai.png diff --git a/tests/ref/link-basic.png b/tests/ref/link-basic.png Binary files differnew file mode 100644 index 00000000..d16c7ef1 --- /dev/null +++ b/tests/ref/link-basic.png diff --git a/tests/ref/link-bracket-balanced.png b/tests/ref/link-bracket-balanced.png Binary files differnew file mode 100644 index 00000000..048a7c52 --- /dev/null +++ b/tests/ref/link-bracket-balanced.png diff --git a/tests/ref/link-bracket-unbalanced-closing.png b/tests/ref/link-bracket-unbalanced-closing.png Binary files differnew file mode 100644 index 00000000..e1c1341c --- /dev/null +++ b/tests/ref/link-bracket-unbalanced-closing.png diff --git a/tests/ref/link-on-block.png b/tests/ref/link-on-block.png Binary files differnew file mode 100644 index 00000000..9076983d --- /dev/null +++ b/tests/ref/link-on-block.png diff --git a/tests/ref/link-show.png b/tests/ref/link-show.png Binary files differnew file mode 100644 index 00000000..59542bad --- /dev/null +++ b/tests/ref/link-show.png diff --git a/tests/ref/link-to-label.png b/tests/ref/link-to-label.png Binary files differnew file mode 100644 index 00000000..f6075526 --- /dev/null +++ b/tests/ref/link-to-label.png diff --git a/tests/ref/link-to-page.png b/tests/ref/link-to-page.png Binary files differnew file mode 100644 index 00000000..bbd2f103 --- /dev/null +++ b/tests/ref/link-to-page.png diff --git a/tests/ref/link-trailing-period.png b/tests/ref/link-trailing-period.png Binary files differnew file mode 100644 index 00000000..4dd11f34 --- /dev/null +++ b/tests/ref/link-trailing-period.png diff --git a/tests/ref/link-transformed.png b/tests/ref/link-transformed.png Binary files differnew file mode 100644 index 00000000..6b94b5cb --- /dev/null +++ b/tests/ref/link-transformed.png diff --git a/tests/ref/list-attached-above-spacing.png b/tests/ref/list-attached-above-spacing.png Binary files differnew file mode 100644 index 00000000..0f499769 --- /dev/null +++ b/tests/ref/list-attached-above-spacing.png diff --git a/tests/ref/list-attached.png b/tests/ref/list-attached.png Binary files differnew file mode 100644 index 00000000..c1735fd0 --- /dev/null +++ b/tests/ref/list-attached.png diff --git a/tests/ref/list-basic.png b/tests/ref/list-basic.png Binary files differnew file mode 100644 index 00000000..edf69cac --- /dev/null +++ b/tests/ref/list-basic.png diff --git a/tests/ref/list-content-block.png b/tests/ref/list-content-block.png Binary files differnew file mode 100644 index 00000000..18b003e5 --- /dev/null +++ b/tests/ref/list-content-block.png diff --git a/tests/ref/list-indent-specifics.png b/tests/ref/list-indent-specifics.png Binary files differnew file mode 100644 index 00000000..212e45ed --- /dev/null +++ b/tests/ref/list-indent-specifics.png diff --git a/tests/ref/list-marker-align-unaffected.png b/tests/ref/list-marker-align-unaffected.png Binary files differnew file mode 100644 index 00000000..90f9ad45 --- /dev/null +++ b/tests/ref/list-marker-align-unaffected.png diff --git a/tests/ref/list-marker-bare-hyphen.png b/tests/ref/list-marker-bare-hyphen.png Binary files differnew file mode 100644 index 00000000..37830fd6 --- /dev/null +++ b/tests/ref/list-marker-bare-hyphen.png diff --git a/tests/ref/list-marker-closure.png b/tests/ref/list-marker-closure.png Binary files differnew file mode 100644 index 00000000..4dba3b9d --- /dev/null +++ b/tests/ref/list-marker-closure.png diff --git a/tests/ref/list-marker-cycle.png b/tests/ref/list-marker-cycle.png Binary files differnew file mode 100644 index 00000000..ef219f07 --- /dev/null +++ b/tests/ref/list-marker-cycle.png diff --git a/tests/ref/list-marker-dash.png b/tests/ref/list-marker-dash.png Binary files differnew file mode 100644 index 00000000..10abc8a6 --- /dev/null +++ b/tests/ref/list-marker-dash.png diff --git a/tests/ref/list-mix.png b/tests/ref/list-mix.png Binary files differnew file mode 100644 index 00000000..0f2b03cf --- /dev/null +++ b/tests/ref/list-mix.png diff --git a/tests/ref/list-mixed-tabs-and-spaces.png b/tests/ref/list-mixed-tabs-and-spaces.png Binary files differnew file mode 100644 index 00000000..fcddff42 --- /dev/null +++ b/tests/ref/list-mixed-tabs-and-spaces.png diff --git a/tests/ref/list-nested.png b/tests/ref/list-nested.png Binary files differnew file mode 100644 index 00000000..22f73ecb --- /dev/null +++ b/tests/ref/list-nested.png diff --git a/tests/ref/list-non-attached-followed-by-attached.png b/tests/ref/list-non-attached-followed-by-attached.png Binary files differnew file mode 100644 index 00000000..22db4e38 --- /dev/null +++ b/tests/ref/list-non-attached-followed-by-attached.png diff --git a/tests/ref/list-rtl.png b/tests/ref/list-rtl.png Binary files differnew file mode 100644 index 00000000..db1e7546 --- /dev/null +++ b/tests/ref/list-rtl.png diff --git a/tests/ref/list-syntax-edge-cases.png b/tests/ref/list-syntax-edge-cases.png Binary files differnew file mode 100644 index 00000000..460462e3 --- /dev/null +++ b/tests/ref/list-syntax-edge-cases.png diff --git a/tests/ref/list-tabs.png b/tests/ref/list-tabs.png Binary files differnew file mode 100644 index 00000000..1fce74c3 --- /dev/null +++ b/tests/ref/list-tabs.png diff --git a/tests/ref/list-tight-non-attached-tight.png b/tests/ref/list-tight-non-attached-tight.png Binary files differnew file mode 100644 index 00000000..96d51813 --- /dev/null +++ b/tests/ref/list-tight-non-attached-tight.png diff --git a/tests/ref/list-top-level-indent.png b/tests/ref/list-top-level-indent.png Binary files differnew file mode 100644 index 00000000..beb17ede --- /dev/null +++ b/tests/ref/list-top-level-indent.png diff --git a/tests/ref/list-wide-cannot-attach.png b/tests/ref/list-wide-cannot-attach.png Binary files differnew file mode 100644 index 00000000..600041a7 --- /dev/null +++ b/tests/ref/list-wide-cannot-attach.png diff --git a/tests/ref/list-wide-really-cannot-attach.png b/tests/ref/list-wide-really-cannot-attach.png Binary files differnew file mode 100644 index 00000000..89680c09 --- /dev/null +++ b/tests/ref/list-wide-really-cannot-attach.png diff --git a/tests/ref/locate-element-selector.png b/tests/ref/locate-element-selector.png Binary files differnew file mode 100644 index 00000000..fc36ddff --- /dev/null +++ b/tests/ref/locate-element-selector.png diff --git a/tests/ref/locate-position.png b/tests/ref/locate-position.png Binary files differnew file mode 100644 index 00000000..fc36ddff --- /dev/null +++ b/tests/ref/locate-position.png diff --git a/tests/ref/loop-break-join-in-first-arg.png b/tests/ref/loop-break-join-in-first-arg.png Binary files differnew file mode 100644 index 00000000..fbad2125 --- /dev/null +++ b/tests/ref/loop-break-join-in-first-arg.png diff --git a/tests/ref/loop-break-join-in-nested-blocks.png b/tests/ref/loop-break-join-in-nested-blocks.png Binary files differnew file mode 100644 index 00000000..6e2af47a --- /dev/null +++ b/tests/ref/loop-break-join-in-nested-blocks.png diff --git a/tests/ref/loop-break-join-in-set-rule-args.png b/tests/ref/loop-break-join-in-set-rule-args.png Binary files differnew file mode 100644 index 00000000..37e13773 --- /dev/null +++ b/tests/ref/loop-break-join-in-set-rule-args.png diff --git a/tests/ref/loop-break-join-set-and-show.png b/tests/ref/loop-break-join-set-and-show.png Binary files differnew file mode 100644 index 00000000..8c81c147 --- /dev/null +++ b/tests/ref/loop-break-join-set-and-show.png diff --git a/tests/ref/lorem-pars.png b/tests/ref/lorem-pars.png Binary files differnew file mode 100644 index 00000000..5ff0a345 --- /dev/null +++ b/tests/ref/lorem-pars.png diff --git a/tests/ref/lorem.png b/tests/ref/lorem.png Binary files differnew file mode 100644 index 00000000..197acb1c --- /dev/null +++ b/tests/ref/lorem.png diff --git a/tests/ref/math-accent-align.png b/tests/ref/math-accent-align.png Binary files differnew file mode 100644 index 00000000..84e8dc8c --- /dev/null +++ b/tests/ref/math-accent-align.png diff --git a/tests/ref/math-accent-bounds.png b/tests/ref/math-accent-bounds.png Binary files differnew file mode 100644 index 00000000..d9876182 --- /dev/null +++ b/tests/ref/math-accent-bounds.png diff --git a/tests/ref/math-accent-func.png b/tests/ref/math-accent-func.png Binary files differnew file mode 100644 index 00000000..00821f70 --- /dev/null +++ b/tests/ref/math-accent-func.png diff --git a/tests/ref/math-accent-high-base.png b/tests/ref/math-accent-high-base.png Binary files differnew file mode 100644 index 00000000..f4d7580f --- /dev/null +++ b/tests/ref/math-accent-high-base.png diff --git a/tests/ref/math-accent-sized.png b/tests/ref/math-accent-sized.png Binary files differnew file mode 100644 index 00000000..76783b25 --- /dev/null +++ b/tests/ref/math-accent-sized.png diff --git a/tests/ref/math-accent-superscript.png b/tests/ref/math-accent-superscript.png Binary files differnew file mode 100644 index 00000000..8ddf113d --- /dev/null +++ b/tests/ref/math-accent-superscript.png diff --git a/tests/ref/math-accent-sym-call.png b/tests/ref/math-accent-sym-call.png Binary files differnew file mode 100644 index 00000000..0837a86c --- /dev/null +++ b/tests/ref/math-accent-sym-call.png diff --git a/tests/ref/math-accent-wide-base.png b/tests/ref/math-accent-wide-base.png Binary files differnew file mode 100644 index 00000000..af716bf4 --- /dev/null +++ b/tests/ref/math-accent-wide-base.png diff --git a/tests/ref/math-align-aligned-in-source.png b/tests/ref/math-align-aligned-in-source.png Binary files differnew file mode 100644 index 00000000..958a42c5 --- /dev/null +++ b/tests/ref/math-align-aligned-in-source.png diff --git a/tests/ref/math-align-basic.png b/tests/ref/math-align-basic.png Binary files differnew file mode 100644 index 00000000..cf4a8d6a --- /dev/null +++ b/tests/ref/math-align-basic.png diff --git a/tests/ref/math-align-cases.png b/tests/ref/math-align-cases.png Binary files differnew file mode 100644 index 00000000..4ea9a264 --- /dev/null +++ b/tests/ref/math-align-cases.png diff --git a/tests/ref/math-align-implicit.png b/tests/ref/math-align-implicit.png Binary files differnew file mode 100644 index 00000000..05a0d98d --- /dev/null +++ b/tests/ref/math-align-implicit.png diff --git a/tests/ref/math-align-lines-mixed.png b/tests/ref/math-align-lines-mixed.png Binary files differnew file mode 100644 index 00000000..d50af28c --- /dev/null +++ b/tests/ref/math-align-lines-mixed.png diff --git a/tests/ref/math-align-post-fix.png b/tests/ref/math-align-post-fix.png Binary files differnew file mode 100644 index 00000000..33bc3da7 --- /dev/null +++ b/tests/ref/math-align-post-fix.png diff --git a/tests/ref/math-align-toggle.png b/tests/ref/math-align-toggle.png Binary files differnew file mode 100644 index 00000000..24448ab5 --- /dev/null +++ b/tests/ref/math-align-toggle.png diff --git a/tests/ref/math-align-weird.png b/tests/ref/math-align-weird.png Binary files differnew file mode 100644 index 00000000..672742ec --- /dev/null +++ b/tests/ref/math-align-weird.png diff --git a/tests/ref/math-align-wider-first-column.png b/tests/ref/math-align-wider-first-column.png Binary files differnew file mode 100644 index 00000000..46c9c3ff --- /dev/null +++ b/tests/ref/math-align-wider-first-column.png diff --git a/tests/ref/math-attach-default-placement.png b/tests/ref/math-attach-default-placement.png Binary files differnew file mode 100644 index 00000000..685fb550 --- /dev/null +++ b/tests/ref/math-attach-default-placement.png diff --git a/tests/ref/math-attach-descender-collision.png b/tests/ref/math-attach-descender-collision.png Binary files differnew file mode 100644 index 00000000..71654916 --- /dev/null +++ b/tests/ref/math-attach-descender-collision.png diff --git a/tests/ref/math-attach-followed-by-func-call.png b/tests/ref/math-attach-followed-by-func-call.png Binary files differnew file mode 100644 index 00000000..71d78c16 --- /dev/null +++ b/tests/ref/math-attach-followed-by-func-call.png diff --git a/tests/ref/math-attach-force-scripts-and-limits.png b/tests/ref/math-attach-force-scripts-and-limits.png Binary files differnew file mode 100644 index 00000000..21a1050f --- /dev/null +++ b/tests/ref/math-attach-force-scripts-and-limits.png diff --git a/tests/ref/math-attach-high.png b/tests/ref/math-attach-high.png Binary files differnew file mode 100644 index 00000000..4bb6cb29 --- /dev/null +++ b/tests/ref/math-attach-high.png diff --git a/tests/ref/math-attach-horizontal-align.png b/tests/ref/math-attach-horizontal-align.png Binary files differnew file mode 100644 index 00000000..507cb0ff --- /dev/null +++ b/tests/ref/math-attach-horizontal-align.png diff --git a/tests/ref/math-attach-integral.png b/tests/ref/math-attach-integral.png Binary files differnew file mode 100644 index 00000000..baebf44c --- /dev/null +++ b/tests/ref/math-attach-integral.png diff --git a/tests/ref/math-attach-large-operator.png b/tests/ref/math-attach-large-operator.png Binary files differnew file mode 100644 index 00000000..774b603c --- /dev/null +++ b/tests/ref/math-attach-large-operator.png diff --git a/tests/ref/math-attach-limit.png b/tests/ref/math-attach-limit.png Binary files differnew file mode 100644 index 00000000..5f9f24d7 --- /dev/null +++ b/tests/ref/math-attach-limit.png diff --git a/tests/ref/math-attach-mixed.png b/tests/ref/math-attach-mixed.png Binary files differnew file mode 100644 index 00000000..4be327e3 --- /dev/null +++ b/tests/ref/math-attach-mixed.png diff --git a/tests/ref/math-attach-nested.png b/tests/ref/math-attach-nested.png Binary files differnew file mode 100644 index 00000000..8b4309cf --- /dev/null +++ b/tests/ref/math-attach-nested.png diff --git a/tests/ref/math-attach-postscripts.png b/tests/ref/math-attach-postscripts.png Binary files differnew file mode 100644 index 00000000..bd94e4bd --- /dev/null +++ b/tests/ref/math-attach-postscripts.png diff --git a/tests/ref/math-attach-prescripts.png b/tests/ref/math-attach-prescripts.png Binary files differnew file mode 100644 index 00000000..cd105e9d --- /dev/null +++ b/tests/ref/math-attach-prescripts.png diff --git a/tests/ref/math-attach-show-limit.png b/tests/ref/math-attach-show-limit.png Binary files differnew file mode 100644 index 00000000..4ce2b3fb --- /dev/null +++ b/tests/ref/math-attach-show-limit.png diff --git a/tests/ref/math-attach-subscript-multiline.png b/tests/ref/math-attach-subscript-multiline.png Binary files differnew file mode 100644 index 00000000..7f9aec2e --- /dev/null +++ b/tests/ref/math-attach-subscript-multiline.png diff --git a/tests/ref/math-attach-to-group.png b/tests/ref/math-attach-to-group.png Binary files differnew file mode 100644 index 00000000..a3d1923e --- /dev/null +++ b/tests/ref/math-attach-to-group.png diff --git a/tests/ref/math-binom-multiple.png b/tests/ref/math-binom-multiple.png Binary files differnew file mode 100644 index 00000000..7eb60be0 --- /dev/null +++ b/tests/ref/math-binom-multiple.png diff --git a/tests/ref/math-binom.png b/tests/ref/math-binom.png Binary files differnew file mode 100644 index 00000000..85ab08f9 --- /dev/null +++ b/tests/ref/math-binom.png diff --git a/tests/ref/math-box-with-baseline.png b/tests/ref/math-box-with-baseline.png Binary files differnew file mode 100644 index 00000000..e38e6442 --- /dev/null +++ b/tests/ref/math-box-with-baseline.png diff --git a/tests/ref/math-box-without-baseline.png b/tests/ref/math-box-without-baseline.png Binary files differnew file mode 100644 index 00000000..27549587 --- /dev/null +++ b/tests/ref/math-box-without-baseline.png diff --git a/tests/ref/math-call-non-func.png b/tests/ref/math-call-non-func.png Binary files differnew file mode 100644 index 00000000..da46efc9 --- /dev/null +++ b/tests/ref/math-call-non-func.png diff --git a/tests/ref/math-cancel-angle-absolute.png b/tests/ref/math-cancel-angle-absolute.png Binary files differnew file mode 100644 index 00000000..125e59fb --- /dev/null +++ b/tests/ref/math-cancel-angle-absolute.png diff --git a/tests/ref/math-cancel-angle-func.png b/tests/ref/math-cancel-angle-func.png Binary files differnew file mode 100644 index 00000000..54f6e759 --- /dev/null +++ b/tests/ref/math-cancel-angle-func.png diff --git a/tests/ref/math-cancel-cross.png b/tests/ref/math-cancel-cross.png Binary files differnew file mode 100644 index 00000000..49fba664 --- /dev/null +++ b/tests/ref/math-cancel-cross.png diff --git a/tests/ref/math-cancel-customized.png b/tests/ref/math-cancel-customized.png Binary files differnew file mode 100644 index 00000000..9fa5045d --- /dev/null +++ b/tests/ref/math-cancel-customized.png diff --git a/tests/ref/math-cancel-display.png b/tests/ref/math-cancel-display.png Binary files differnew file mode 100644 index 00000000..30d30a59 --- /dev/null +++ b/tests/ref/math-cancel-display.png diff --git a/tests/ref/math-cancel-inline.png b/tests/ref/math-cancel-inline.png Binary files differnew file mode 100644 index 00000000..4d92bc5e --- /dev/null +++ b/tests/ref/math-cancel-inline.png diff --git a/tests/ref/math-cancel-inverted.png b/tests/ref/math-cancel-inverted.png Binary files differnew file mode 100644 index 00000000..129d53a0 --- /dev/null +++ b/tests/ref/math-cancel-inverted.png diff --git a/tests/ref/math-cases-gap.png b/tests/ref/math-cases-gap.png Binary files differnew file mode 100644 index 00000000..e3579130 --- /dev/null +++ b/tests/ref/math-cases-gap.png diff --git a/tests/ref/math-cases.png b/tests/ref/math-cases.png Binary files differnew file mode 100644 index 00000000..2e8c260a --- /dev/null +++ b/tests/ref/math-cases.png diff --git a/tests/ref/math-class-chars.png b/tests/ref/math-class-chars.png Binary files differnew file mode 100644 index 00000000..a4f7d29b --- /dev/null +++ b/tests/ref/math-class-chars.png diff --git a/tests/ref/math-class-content.png b/tests/ref/math-class-content.png Binary files differnew file mode 100644 index 00000000..47603fb4 --- /dev/null +++ b/tests/ref/math-class-content.png diff --git a/tests/ref/math-class-exceptions.png b/tests/ref/math-class-exceptions.png Binary files differnew file mode 100644 index 00000000..8b3ecc81 --- /dev/null +++ b/tests/ref/math-class-exceptions.png diff --git a/tests/ref/math-class-limits.png b/tests/ref/math-class-limits.png Binary files differnew file mode 100644 index 00000000..140acf95 --- /dev/null +++ b/tests/ref/math-class-limits.png diff --git a/tests/ref/math-class-nested.png b/tests/ref/math-class-nested.png Binary files differnew file mode 100644 index 00000000..5847868e --- /dev/null +++ b/tests/ref/math-class-nested.png diff --git a/tests/ref/math-common-symbols.png b/tests/ref/math-common-symbols.png Binary files differnew file mode 100644 index 00000000..22da84b5 --- /dev/null +++ b/tests/ref/math-common-symbols.png diff --git a/tests/ref/math-dif.png b/tests/ref/math-dif.png Binary files differnew file mode 100644 index 00000000..dfe88b3c --- /dev/null +++ b/tests/ref/math-dif.png diff --git a/tests/ref/math-equation-align-numbered.png b/tests/ref/math-equation-align-numbered.png Binary files differnew file mode 100644 index 00000000..e43054c8 --- /dev/null +++ b/tests/ref/math-equation-align-numbered.png diff --git a/tests/ref/math-equation-align-unnumbered.png b/tests/ref/math-equation-align-unnumbered.png Binary files differnew file mode 100644 index 00000000..413da120 --- /dev/null +++ b/tests/ref/math-equation-align-unnumbered.png diff --git a/tests/ref/math-equation-auto-wrapping.png b/tests/ref/math-equation-auto-wrapping.png Binary files differnew file mode 100644 index 00000000..9c600172 --- /dev/null +++ b/tests/ref/math-equation-auto-wrapping.png diff --git a/tests/ref/math-equation-font.png b/tests/ref/math-equation-font.png Binary files differnew file mode 100644 index 00000000..b105d9e3 --- /dev/null +++ b/tests/ref/math-equation-font.png diff --git a/tests/ref/math-equation-number-align-end.png b/tests/ref/math-equation-number-align-end.png Binary files differnew file mode 100644 index 00000000..f60a15ec --- /dev/null +++ b/tests/ref/math-equation-number-align-end.png diff --git a/tests/ref/math-equation-number-align-left.png b/tests/ref/math-equation-number-align-left.png Binary files differnew file mode 100644 index 00000000..a8ed40a5 --- /dev/null +++ b/tests/ref/math-equation-number-align-left.png diff --git a/tests/ref/math-equation-number-align-multiline-bottom.png b/tests/ref/math-equation-number-align-multiline-bottom.png Binary files differnew file mode 100644 index 00000000..cb0e5daa --- /dev/null +++ b/tests/ref/math-equation-number-align-multiline-bottom.png diff --git a/tests/ref/math-equation-number-align-multiline-expand.png b/tests/ref/math-equation-number-align-multiline-expand.png Binary files differnew file mode 100644 index 00000000..3c3cdc05 --- /dev/null +++ b/tests/ref/math-equation-number-align-multiline-expand.png diff --git a/tests/ref/math-equation-number-align-multiline-top-start.png b/tests/ref/math-equation-number-align-multiline-top-start.png Binary files differnew file mode 100644 index 00000000..43346de9 --- /dev/null +++ b/tests/ref/math-equation-number-align-multiline-top-start.png diff --git a/tests/ref/math-equation-number-align-multiline.png b/tests/ref/math-equation-number-align-multiline.png Binary files differnew file mode 100644 index 00000000..a46bc1e9 --- /dev/null +++ b/tests/ref/math-equation-number-align-multiline.png diff --git a/tests/ref/math-equation-number-align-right.png b/tests/ref/math-equation-number-align-right.png Binary files differnew file mode 100644 index 00000000..e3d588c4 --- /dev/null +++ b/tests/ref/math-equation-number-align-right.png diff --git a/tests/ref/math-equation-number-align-start.png b/tests/ref/math-equation-number-align-start.png Binary files differnew file mode 100644 index 00000000..67ed3c4c --- /dev/null +++ b/tests/ref/math-equation-number-align-start.png diff --git a/tests/ref/math-equation-number-align.png b/tests/ref/math-equation-number-align.png Binary files differnew file mode 100644 index 00000000..f60a15ec --- /dev/null +++ b/tests/ref/math-equation-number-align.png diff --git a/tests/ref/math-equation-numbering.png b/tests/ref/math-equation-numbering.png Binary files differnew file mode 100644 index 00000000..b1e6b10e --- /dev/null +++ b/tests/ref/math-equation-numbering.png diff --git a/tests/ref/math-equation-show-rule.png b/tests/ref/math-equation-show-rule.png Binary files differnew file mode 100644 index 00000000..26da7cd1 --- /dev/null +++ b/tests/ref/math-equation-show-rule.png diff --git a/tests/ref/math-font-fallback.png b/tests/ref/math-font-fallback.png Binary files differnew file mode 100644 index 00000000..50fa85c7 --- /dev/null +++ b/tests/ref/math-font-fallback.png diff --git a/tests/ref/math-font-features.png b/tests/ref/math-font-features.png Binary files differnew file mode 100644 index 00000000..0fd5e6e1 --- /dev/null +++ b/tests/ref/math-font-features.png diff --git a/tests/ref/math-font-switch.png b/tests/ref/math-font-switch.png Binary files differnew file mode 100644 index 00000000..4c572ea5 --- /dev/null +++ b/tests/ref/math-font-switch.png diff --git a/tests/ref/math-frac-associativity.png b/tests/ref/math-frac-associativity.png Binary files differnew file mode 100644 index 00000000..a5daca59 --- /dev/null +++ b/tests/ref/math-frac-associativity.png diff --git a/tests/ref/math-frac-baseline.png b/tests/ref/math-frac-baseline.png Binary files differnew file mode 100644 index 00000000..d65e2c33 --- /dev/null +++ b/tests/ref/math-frac-baseline.png diff --git a/tests/ref/math-frac-large.png b/tests/ref/math-frac-large.png Binary files differnew file mode 100644 index 00000000..ff9520f3 --- /dev/null +++ b/tests/ref/math-frac-large.png diff --git a/tests/ref/math-frac-paren-removal.png b/tests/ref/math-frac-paren-removal.png Binary files differnew file mode 100644 index 00000000..4f58f1d3 --- /dev/null +++ b/tests/ref/math-frac-paren-removal.png diff --git a/tests/ref/math-frac-precedence.png b/tests/ref/math-frac-precedence.png Binary files differnew file mode 100644 index 00000000..236b9989 --- /dev/null +++ b/tests/ref/math-frac-precedence.png diff --git a/tests/ref/math-linebreaking-after-binop-and-rel.png b/tests/ref/math-linebreaking-after-binop-and-rel.png Binary files differnew file mode 100644 index 00000000..1cdd73c4 --- /dev/null +++ b/tests/ref/math-linebreaking-after-binop-and-rel.png diff --git a/tests/ref/math-linebreaking-after-relation-without-space.png b/tests/ref/math-linebreaking-after-relation-without-space.png Binary files differnew file mode 100644 index 00000000..7c569ad1 --- /dev/null +++ b/tests/ref/math-linebreaking-after-relation-without-space.png diff --git a/tests/ref/math-linebreaking-between-consecutive-relations.png b/tests/ref/math-linebreaking-between-consecutive-relations.png Binary files differnew file mode 100644 index 00000000..ba222c57 --- /dev/null +++ b/tests/ref/math-linebreaking-between-consecutive-relations.png diff --git a/tests/ref/math-linebreaking-empty.png b/tests/ref/math-linebreaking-empty.png Binary files differnew file mode 100644 index 00000000..8fd4dbb9 --- /dev/null +++ b/tests/ref/math-linebreaking-empty.png diff --git a/tests/ref/math-linebreaking-in-box.png b/tests/ref/math-linebreaking-in-box.png Binary files differnew file mode 100644 index 00000000..e026f1a2 --- /dev/null +++ b/tests/ref/math-linebreaking-in-box.png diff --git a/tests/ref/math-linebreaking-lr.png b/tests/ref/math-linebreaking-lr.png Binary files differnew file mode 100644 index 00000000..69f08e7e --- /dev/null +++ b/tests/ref/math-linebreaking-lr.png diff --git a/tests/ref/math-linebreaking-multiline.png b/tests/ref/math-linebreaking-multiline.png Binary files differnew file mode 100644 index 00000000..cd5f2fce --- /dev/null +++ b/tests/ref/math-linebreaking-multiline.png diff --git a/tests/ref/math-linebreaking-trailing-linebreak.png b/tests/ref/math-linebreaking-trailing-linebreak.png Binary files differnew file mode 100644 index 00000000..4a50832b --- /dev/null +++ b/tests/ref/math-linebreaking-trailing-linebreak.png diff --git a/tests/ref/math-lr-call.png b/tests/ref/math-lr-call.png Binary files differnew file mode 100644 index 00000000..baf668d4 --- /dev/null +++ b/tests/ref/math-lr-call.png diff --git a/tests/ref/math-lr-color.png b/tests/ref/math-lr-color.png Binary files differnew file mode 100644 index 00000000..66876819 --- /dev/null +++ b/tests/ref/math-lr-color.png diff --git a/tests/ref/math-lr-fences.png b/tests/ref/math-lr-fences.png Binary files differnew file mode 100644 index 00000000..32314cb4 --- /dev/null +++ b/tests/ref/math-lr-fences.png diff --git a/tests/ref/math-lr-half.png b/tests/ref/math-lr-half.png Binary files differnew file mode 100644 index 00000000..311188b4 --- /dev/null +++ b/tests/ref/math-lr-half.png diff --git a/tests/ref/math-lr-matching.png b/tests/ref/math-lr-matching.png Binary files differnew file mode 100644 index 00000000..e5fd4c7b --- /dev/null +++ b/tests/ref/math-lr-matching.png diff --git a/tests/ref/math-lr-mid.png b/tests/ref/math-lr-mid.png Binary files differnew file mode 100644 index 00000000..e4f1e671 --- /dev/null +++ b/tests/ref/math-lr-mid.png diff --git a/tests/ref/math-lr-shorthands.png b/tests/ref/math-lr-shorthands.png Binary files differnew file mode 100644 index 00000000..d8961672 --- /dev/null +++ b/tests/ref/math-lr-shorthands.png diff --git a/tests/ref/math-lr-size.png b/tests/ref/math-lr-size.png Binary files differnew file mode 100644 index 00000000..09d24421 --- /dev/null +++ b/tests/ref/math-lr-size.png diff --git a/tests/ref/math-lr-symbol-unmatched.png b/tests/ref/math-lr-symbol-unmatched.png Binary files differnew file mode 100644 index 00000000..38d0a988 --- /dev/null +++ b/tests/ref/math-lr-symbol-unmatched.png diff --git a/tests/ref/math-lr-unbalanced.png b/tests/ref/math-lr-unbalanced.png Binary files differnew file mode 100644 index 00000000..eff579ba --- /dev/null +++ b/tests/ref/math-lr-unbalanced.png diff --git a/tests/ref/math-lr-unmatched.png b/tests/ref/math-lr-unmatched.png Binary files differnew file mode 100644 index 00000000..9a0f3275 --- /dev/null +++ b/tests/ref/math-lr-unmatched.png diff --git a/tests/ref/math-lr-weak-spacing.png b/tests/ref/math-lr-weak-spacing.png Binary files differnew file mode 100644 index 00000000..871aaa2e --- /dev/null +++ b/tests/ref/math-lr-weak-spacing.png diff --git a/tests/ref/math-mat-align-complex.png b/tests/ref/math-mat-align-complex.png Binary files differnew file mode 100644 index 00000000..682fed22 --- /dev/null +++ b/tests/ref/math-mat-align-complex.png diff --git a/tests/ref/math-mat-align-explicit--alternating.png b/tests/ref/math-mat-align-explicit--alternating.png Binary files differnew file mode 100644 index 00000000..cb29eb06 --- /dev/null +++ b/tests/ref/math-mat-align-explicit--alternating.png diff --git a/tests/ref/math-mat-align-explicit-left.png b/tests/ref/math-mat-align-explicit-left.png Binary files differnew file mode 100644 index 00000000..97fe0a1f --- /dev/null +++ b/tests/ref/math-mat-align-explicit-left.png diff --git a/tests/ref/math-mat-align-explicit-right.png b/tests/ref/math-mat-align-explicit-right.png Binary files differnew file mode 100644 index 00000000..80966e52 --- /dev/null +++ b/tests/ref/math-mat-align-explicit-right.png diff --git a/tests/ref/math-mat-align-implicit.png b/tests/ref/math-mat-align-implicit.png Binary files differnew file mode 100644 index 00000000..0c14f1a7 --- /dev/null +++ b/tests/ref/math-mat-align-implicit.png diff --git a/tests/ref/math-mat-align-signed-numbers.png b/tests/ref/math-mat-align-signed-numbers.png Binary files differnew file mode 100644 index 00000000..02a3c582 --- /dev/null +++ b/tests/ref/math-mat-align-signed-numbers.png diff --git a/tests/ref/math-mat-augment-set.png b/tests/ref/math-mat-augment-set.png Binary files differnew file mode 100644 index 00000000..f3827c41 --- /dev/null +++ b/tests/ref/math-mat-augment-set.png diff --git a/tests/ref/math-mat-augment.png b/tests/ref/math-mat-augment.png Binary files differnew file mode 100644 index 00000000..3a272ce9 --- /dev/null +++ b/tests/ref/math-mat-augment.png diff --git a/tests/ref/math-mat-baseline.png b/tests/ref/math-mat-baseline.png Binary files differnew file mode 100644 index 00000000..51e90a1f --- /dev/null +++ b/tests/ref/math-mat-baseline.png diff --git a/tests/ref/math-mat-delim-direct.png b/tests/ref/math-mat-delim-direct.png Binary files differnew file mode 100644 index 00000000..b40fd36c --- /dev/null +++ b/tests/ref/math-mat-delim-direct.png diff --git a/tests/ref/math-mat-delim-set.png b/tests/ref/math-mat-delim-set.png Binary files differnew file mode 100644 index 00000000..fc92fd4b --- /dev/null +++ b/tests/ref/math-mat-delim-set.png diff --git a/tests/ref/math-mat-gap.png b/tests/ref/math-mat-gap.png Binary files differnew file mode 100644 index 00000000..5eb8460d --- /dev/null +++ b/tests/ref/math-mat-gap.png diff --git a/tests/ref/math-mat-gaps.png b/tests/ref/math-mat-gaps.png Binary files differnew file mode 100644 index 00000000..38cf5247 --- /dev/null +++ b/tests/ref/math-mat-gaps.png diff --git a/tests/ref/math-mat-semicolon.png b/tests/ref/math-mat-semicolon.png Binary files differnew file mode 100644 index 00000000..abb5d1df --- /dev/null +++ b/tests/ref/math-mat-semicolon.png diff --git a/tests/ref/math-mat-sparse.png b/tests/ref/math-mat-sparse.png Binary files differnew file mode 100644 index 00000000..4d077931 --- /dev/null +++ b/tests/ref/math-mat-sparse.png diff --git a/tests/ref/math-multiline-multiple-trailing-linebreaks.png b/tests/ref/math-multiline-multiple-trailing-linebreaks.png Binary files differnew file mode 100644 index 00000000..2c6484c7 --- /dev/null +++ b/tests/ref/math-multiline-multiple-trailing-linebreaks.png diff --git a/tests/ref/math-multiline-no-trailing-linebreak.png b/tests/ref/math-multiline-no-trailing-linebreak.png Binary files differnew file mode 100644 index 00000000..8ad6204d --- /dev/null +++ b/tests/ref/math-multiline-no-trailing-linebreak.png diff --git a/tests/ref/math-multiline-trailing-linebreak.png b/tests/ref/math-multiline-trailing-linebreak.png Binary files differnew file mode 100644 index 00000000..364d8624 --- /dev/null +++ b/tests/ref/math-multiline-trailing-linebreak.png diff --git a/tests/ref/math-nested-normal-layout.png b/tests/ref/math-nested-normal-layout.png Binary files differnew file mode 100644 index 00000000..4ec7d46e --- /dev/null +++ b/tests/ref/math-nested-normal-layout.png diff --git a/tests/ref/math-non-math-content.png b/tests/ref/math-non-math-content.png Binary files differnew file mode 100644 index 00000000..66896d18 --- /dev/null +++ b/tests/ref/math-non-math-content.png diff --git a/tests/ref/math-op-call.png b/tests/ref/math-op-call.png Binary files differnew file mode 100644 index 00000000..2fcdf2cb --- /dev/null +++ b/tests/ref/math-op-call.png diff --git a/tests/ref/math-op-custom.png b/tests/ref/math-op-custom.png Binary files differnew file mode 100644 index 00000000..fbba241d --- /dev/null +++ b/tests/ref/math-op-custom.png diff --git a/tests/ref/math-op-predefined.png b/tests/ref/math-op-predefined.png Binary files differnew file mode 100644 index 00000000..bfede9e7 --- /dev/null +++ b/tests/ref/math-op-predefined.png diff --git a/tests/ref/math-op-scripts-vs-limits.png b/tests/ref/math-op-scripts-vs-limits.png Binary files differnew file mode 100644 index 00000000..41897416 --- /dev/null +++ b/tests/ref/math-op-scripts-vs-limits.png diff --git a/tests/ref/math-op-styled.png b/tests/ref/math-op-styled.png Binary files differnew file mode 100644 index 00000000..c6890d74 --- /dev/null +++ b/tests/ref/math-op-styled.png diff --git a/tests/ref/math-optical-size-frac-script-script.png b/tests/ref/math-optical-size-frac-script-script.png Binary files differnew file mode 100644 index 00000000..893b3434 --- /dev/null +++ b/tests/ref/math-optical-size-frac-script-script.png diff --git a/tests/ref/math-optical-size-nested-scripts.png b/tests/ref/math-optical-size-nested-scripts.png Binary files differnew file mode 100644 index 00000000..8ca35c6e --- /dev/null +++ b/tests/ref/math-optical-size-nested-scripts.png diff --git a/tests/ref/math-optical-size-prime-large-operator.png b/tests/ref/math-optical-size-prime-large-operator.png Binary files differnew file mode 100644 index 00000000..b38a934e --- /dev/null +++ b/tests/ref/math-optical-size-prime-large-operator.png diff --git a/tests/ref/math-optical-size-primes.png b/tests/ref/math-optical-size-primes.png Binary files differnew file mode 100644 index 00000000..8fc199aa --- /dev/null +++ b/tests/ref/math-optical-size-primes.png diff --git a/tests/ref/math-primes-after-code-expr.png b/tests/ref/math-primes-after-code-expr.png Binary files differnew file mode 100644 index 00000000..5ec3bc8c --- /dev/null +++ b/tests/ref/math-primes-after-code-expr.png diff --git a/tests/ref/math-primes-attach.png b/tests/ref/math-primes-attach.png Binary files differnew file mode 100644 index 00000000..95b77882 --- /dev/null +++ b/tests/ref/math-primes-attach.png diff --git a/tests/ref/math-primes-complex.png b/tests/ref/math-primes-complex.png Binary files differnew file mode 100644 index 00000000..5f5558eb --- /dev/null +++ b/tests/ref/math-primes-complex.png diff --git a/tests/ref/math-primes-limits.png b/tests/ref/math-primes-limits.png Binary files differnew file mode 100644 index 00000000..f2c5cec2 --- /dev/null +++ b/tests/ref/math-primes-limits.png diff --git a/tests/ref/math-primes-scripts.png b/tests/ref/math-primes-scripts.png Binary files differnew file mode 100644 index 00000000..2a912180 --- /dev/null +++ b/tests/ref/math-primes-scripts.png diff --git a/tests/ref/math-primes-spaces.png b/tests/ref/math-primes-spaces.png Binary files differnew file mode 100644 index 00000000..890cc348 --- /dev/null +++ b/tests/ref/math-primes-spaces.png diff --git a/tests/ref/math-primes.png b/tests/ref/math-primes.png Binary files differnew file mode 100644 index 00000000..f3323197 --- /dev/null +++ b/tests/ref/math-primes.png diff --git a/tests/ref/math-root-basic.png b/tests/ref/math-root-basic.png Binary files differnew file mode 100644 index 00000000..b8b891eb --- /dev/null +++ b/tests/ref/math-root-basic.png diff --git a/tests/ref/math-root-large-body.png b/tests/ref/math-root-large-body.png Binary files differnew file mode 100644 index 00000000..3dd4d848 --- /dev/null +++ b/tests/ref/math-root-large-body.png diff --git a/tests/ref/math-root-large-index.png b/tests/ref/math-root-large-index.png Binary files differnew file mode 100644 index 00000000..8037222c --- /dev/null +++ b/tests/ref/math-root-large-index.png diff --git a/tests/ref/math-root-precomposed.png b/tests/ref/math-root-precomposed.png Binary files differnew file mode 100644 index 00000000..e09f1878 --- /dev/null +++ b/tests/ref/math-root-precomposed.png diff --git a/tests/ref/math-root-radical-attachment.png b/tests/ref/math-root-radical-attachment.png Binary files differnew file mode 100644 index 00000000..4cb447ec --- /dev/null +++ b/tests/ref/math-root-radical-attachment.png diff --git a/tests/ref/math-root-syntax.png b/tests/ref/math-root-syntax.png Binary files differnew file mode 100644 index 00000000..49255493 --- /dev/null +++ b/tests/ref/math-root-syntax.png diff --git a/tests/ref/math-shorthandes.png b/tests/ref/math-shorthandes.png Binary files differnew file mode 100644 index 00000000..ff26ce96 --- /dev/null +++ b/tests/ref/math-shorthandes.png diff --git a/tests/ref/math-size.png b/tests/ref/math-size.png Binary files differnew file mode 100644 index 00000000..b44e4c74 --- /dev/null +++ b/tests/ref/math-size.png diff --git a/tests/ref/math-spacing-basic.png b/tests/ref/math-spacing-basic.png Binary files differnew file mode 100644 index 00000000..5567b087 --- /dev/null +++ b/tests/ref/math-spacing-basic.png diff --git a/tests/ref/math-spacing-decorated.png b/tests/ref/math-spacing-decorated.png Binary files differnew file mode 100644 index 00000000..e34066ea --- /dev/null +++ b/tests/ref/math-spacing-decorated.png diff --git a/tests/ref/math-spacing-kept-spaces.png b/tests/ref/math-spacing-kept-spaces.png Binary files differnew file mode 100644 index 00000000..bb433d4f --- /dev/null +++ b/tests/ref/math-spacing-kept-spaces.png diff --git a/tests/ref/math-spacing-predefined.png b/tests/ref/math-spacing-predefined.png Binary files differnew file mode 100644 index 00000000..244e7642 --- /dev/null +++ b/tests/ref/math-spacing-predefined.png diff --git a/tests/ref/math-spacing-set-comprehension.png b/tests/ref/math-spacing-set-comprehension.png Binary files differnew file mode 100644 index 00000000..63ef46ca --- /dev/null +++ b/tests/ref/math-spacing-set-comprehension.png diff --git a/tests/ref/math-spacing-weak.png b/tests/ref/math-spacing-weak.png Binary files differnew file mode 100644 index 00000000..71af3222 --- /dev/null +++ b/tests/ref/math-spacing-weak.png diff --git a/tests/ref/math-style-exceptions.png b/tests/ref/math-style-exceptions.png Binary files differnew file mode 100644 index 00000000..bdeabb67 --- /dev/null +++ b/tests/ref/math-style-exceptions.png diff --git a/tests/ref/math-style-greek-exceptions.png b/tests/ref/math-style-greek-exceptions.png Binary files differnew file mode 100644 index 00000000..93ae6309 --- /dev/null +++ b/tests/ref/math-style-greek-exceptions.png diff --git a/tests/ref/math-style-hebrew-exceptions.png b/tests/ref/math-style-hebrew-exceptions.png Binary files differnew file mode 100644 index 00000000..723466e8 --- /dev/null +++ b/tests/ref/math-style-hebrew-exceptions.png diff --git a/tests/ref/math-style-italic-default.png b/tests/ref/math-style-italic-default.png Binary files differnew file mode 100644 index 00000000..0a25f6fa --- /dev/null +++ b/tests/ref/math-style-italic-default.png diff --git a/tests/ref/math-style.png b/tests/ref/math-style.png Binary files differnew file mode 100644 index 00000000..f514bd18 --- /dev/null +++ b/tests/ref/math-style.png diff --git a/tests/ref/math-symbol-show-rule.png b/tests/ref/math-symbol-show-rule.png Binary files differnew file mode 100644 index 00000000..68faf937 --- /dev/null +++ b/tests/ref/math-symbol-show-rule.png diff --git a/tests/ref/math-table.png b/tests/ref/math-table.png Binary files differnew file mode 100644 index 00000000..5eb93218 --- /dev/null +++ b/tests/ref/math-table.png diff --git a/tests/ref/math-text-color.png b/tests/ref/math-text-color.png Binary files differnew file mode 100644 index 00000000..33ff00f3 --- /dev/null +++ b/tests/ref/math-text-color.png diff --git a/tests/ref/math-underover-brace.png b/tests/ref/math-underover-brace.png Binary files differnew file mode 100644 index 00000000..d4a3f4a1 --- /dev/null +++ b/tests/ref/math-underover-brace.png diff --git a/tests/ref/math-underover-brackets.png b/tests/ref/math-underover-brackets.png Binary files differnew file mode 100644 index 00000000..03419bc3 --- /dev/null +++ b/tests/ref/math-underover-brackets.png diff --git a/tests/ref/math-underover-line-bracket.png b/tests/ref/math-underover-line-bracket.png Binary files differnew file mode 100644 index 00000000..08d8df20 --- /dev/null +++ b/tests/ref/math-underover-line-bracket.png diff --git a/tests/ref/math-unicode.png b/tests/ref/math-unicode.png Binary files differnew file mode 100644 index 00000000..e74429eb --- /dev/null +++ b/tests/ref/math-unicode.png diff --git a/tests/ref/math-vec-align-explicit-alternating.png b/tests/ref/math-vec-align-explicit-alternating.png Binary files differnew file mode 100644 index 00000000..cb29eb06 --- /dev/null +++ b/tests/ref/math-vec-align-explicit-alternating.png diff --git a/tests/ref/math-vec-delim-set.png b/tests/ref/math-vec-delim-set.png Binary files differnew file mode 100644 index 00000000..8024d594 --- /dev/null +++ b/tests/ref/math-vec-delim-set.png diff --git a/tests/ref/math-vec-gap.png b/tests/ref/math-vec-gap.png Binary files differnew file mode 100644 index 00000000..06f8cf7d --- /dev/null +++ b/tests/ref/math-vec-gap.png diff --git a/tests/ref/math-vec-wide.png b/tests/ref/math-vec-wide.png Binary files differnew file mode 100644 index 00000000..30853a00 --- /dev/null +++ b/tests/ref/math-vec-wide.png diff --git a/tests/ref/math/accent.png b/tests/ref/math/accent.png Binary files differdeleted file mode 100644 index 52a7037e..00000000 --- a/tests/ref/math/accent.png +++ /dev/null diff --git a/tests/ref/math/alignment.png b/tests/ref/math/alignment.png Binary files differdeleted file mode 100644 index 4bf739a4..00000000 --- a/tests/ref/math/alignment.png +++ /dev/null diff --git a/tests/ref/math/attach-p1.png b/tests/ref/math/attach-p1.png Binary files differdeleted file mode 100644 index 45c465ce..00000000 --- a/tests/ref/math/attach-p1.png +++ /dev/null diff --git a/tests/ref/math/attach-p2.png b/tests/ref/math/attach-p2.png Binary files differdeleted file mode 100644 index 3820f33e..00000000 --- a/tests/ref/math/attach-p2.png +++ /dev/null diff --git a/tests/ref/math/attach-p3.png b/tests/ref/math/attach-p3.png Binary files differdeleted file mode 100644 index 69e0a7dd..00000000 --- a/tests/ref/math/attach-p3.png +++ /dev/null diff --git a/tests/ref/math/call.png b/tests/ref/math/call.png Binary files differdeleted file mode 100644 index 907a1a2b..00000000 --- a/tests/ref/math/call.png +++ /dev/null diff --git a/tests/ref/math/cancel.png b/tests/ref/math/cancel.png Binary files differdeleted file mode 100644 index 4f0de136..00000000 --- a/tests/ref/math/cancel.png +++ /dev/null diff --git a/tests/ref/math/cases.png b/tests/ref/math/cases.png Binary files differdeleted file mode 100644 index e222ae17..00000000 --- a/tests/ref/math/cases.png +++ /dev/null diff --git a/tests/ref/math/class.png b/tests/ref/math/class.png Binary files differdeleted file mode 100644 index a4d6e86c..00000000 --- a/tests/ref/math/class.png +++ /dev/null diff --git a/tests/ref/math/content.png b/tests/ref/math/content.png Binary files differdeleted file mode 100644 index c27a17ea..00000000 --- a/tests/ref/math/content.png +++ /dev/null diff --git a/tests/ref/math/delimited.png b/tests/ref/math/delimited.png Binary files differdeleted file mode 100644 index 6126f58a..00000000 --- a/tests/ref/math/delimited.png +++ /dev/null diff --git a/tests/ref/math/equation-block-align.png b/tests/ref/math/equation-block-align.png Binary files differdeleted file mode 100644 index 8736312a..00000000 --- a/tests/ref/math/equation-block-align.png +++ /dev/null diff --git a/tests/ref/math/equation-number.png b/tests/ref/math/equation-number.png Binary files differdeleted file mode 100644 index 8ba91590..00000000 --- a/tests/ref/math/equation-number.png +++ /dev/null diff --git a/tests/ref/math/equation-show.png b/tests/ref/math/equation-show.png Binary files differdeleted file mode 100644 index 79a70dc0..00000000 --- a/tests/ref/math/equation-show.png +++ /dev/null diff --git a/tests/ref/math/font-features.png b/tests/ref/math/font-features.png Binary files differdeleted file mode 100644 index 0ab2c06d..00000000 --- a/tests/ref/math/font-features.png +++ /dev/null diff --git a/tests/ref/math/frac.png b/tests/ref/math/frac.png Binary files differdeleted file mode 100644 index 3e08f7e5..00000000 --- a/tests/ref/math/frac.png +++ /dev/null diff --git a/tests/ref/math/linebreak.png b/tests/ref/math/linebreak.png Binary files differdeleted file mode 100644 index f3212a4a..00000000 --- a/tests/ref/math/linebreak.png +++ /dev/null diff --git a/tests/ref/math/matrix-alignment.png b/tests/ref/math/matrix-alignment.png Binary files differdeleted file mode 100644 index cdf17463..00000000 --- a/tests/ref/math/matrix-alignment.png +++ /dev/null diff --git a/tests/ref/math/matrix-gaps.png b/tests/ref/math/matrix-gaps.png Binary files differdeleted file mode 100644 index 16788969..00000000 --- a/tests/ref/math/matrix-gaps.png +++ /dev/null diff --git a/tests/ref/math/matrix.png b/tests/ref/math/matrix.png Binary files differdeleted file mode 100644 index b8ea19e2..00000000 --- a/tests/ref/math/matrix.png +++ /dev/null diff --git a/tests/ref/math/multiline.png b/tests/ref/math/multiline.png Binary files differdeleted file mode 100644 index 185724af..00000000 --- a/tests/ref/math/multiline.png +++ /dev/null diff --git a/tests/ref/math/numbering.png b/tests/ref/math/numbering.png Binary files differdeleted file mode 100644 index 813f5f8c..00000000 --- a/tests/ref/math/numbering.png +++ /dev/null diff --git a/tests/ref/math/op.png b/tests/ref/math/op.png Binary files differdeleted file mode 100644 index ab3f35f6..00000000 --- a/tests/ref/math/op.png +++ /dev/null diff --git a/tests/ref/math/opticalsize.png b/tests/ref/math/opticalsize.png Binary files differdeleted file mode 100644 index 303f7bee..00000000 --- a/tests/ref/math/opticalsize.png +++ /dev/null diff --git a/tests/ref/math/prime.png b/tests/ref/math/prime.png Binary files differdeleted file mode 100644 index 81a47643..00000000 --- a/tests/ref/math/prime.png +++ /dev/null diff --git a/tests/ref/math/root.png b/tests/ref/math/root.png Binary files differdeleted file mode 100644 index 51fdf2e8..00000000 --- a/tests/ref/math/root.png +++ /dev/null diff --git a/tests/ref/math/spacing.png b/tests/ref/math/spacing.png Binary files differdeleted file mode 100644 index d8198bbf..00000000 --- a/tests/ref/math/spacing.png +++ /dev/null diff --git a/tests/ref/math/style.png b/tests/ref/math/style.png Binary files differdeleted file mode 100644 index a52136dc..00000000 --- a/tests/ref/math/style.png +++ /dev/null diff --git a/tests/ref/math/syntax.png b/tests/ref/math/syntax.png Binary files differdeleted file mode 100644 index 3855fa9b..00000000 --- a/tests/ref/math/syntax.png +++ /dev/null diff --git a/tests/ref/math/unbalanced.png b/tests/ref/math/unbalanced.png Binary files differdeleted file mode 100644 index 84f51837..00000000 --- a/tests/ref/math/unbalanced.png +++ /dev/null diff --git a/tests/ref/math/underover.png b/tests/ref/math/underover.png Binary files differdeleted file mode 100644 index e974302f..00000000 --- a/tests/ref/math/underover.png +++ /dev/null diff --git a/tests/ref/math/vec.png b/tests/ref/math/vec.png Binary files differdeleted file mode 100644 index f2371e5b..00000000 --- a/tests/ref/math/vec.png +++ /dev/null diff --git a/tests/ref/meta/bibliography-full.png b/tests/ref/meta/bibliography-full.png Binary files differdeleted file mode 100644 index d8778c09..00000000 --- a/tests/ref/meta/bibliography-full.png +++ /dev/null diff --git a/tests/ref/meta/bibliography-ordering.png b/tests/ref/meta/bibliography-ordering.png Binary files differdeleted file mode 100644 index 116c561d..00000000 --- a/tests/ref/meta/bibliography-ordering.png +++ /dev/null diff --git a/tests/ref/meta/bibliography.png b/tests/ref/meta/bibliography.png Binary files differdeleted file mode 100644 index 8fbd09bc..00000000 --- a/tests/ref/meta/bibliography.png +++ /dev/null diff --git a/tests/ref/meta/cite-footnote.png b/tests/ref/meta/cite-footnote.png Binary files differdeleted file mode 100644 index 3a7a0094..00000000 --- a/tests/ref/meta/cite-footnote.png +++ /dev/null diff --git a/tests/ref/meta/cite-form.png b/tests/ref/meta/cite-form.png Binary files differdeleted file mode 100644 index 8adeac92..00000000 --- a/tests/ref/meta/cite-form.png +++ /dev/null diff --git a/tests/ref/meta/cite-group.png b/tests/ref/meta/cite-group.png Binary files differdeleted file mode 100644 index 8d02a903..00000000 --- a/tests/ref/meta/cite-group.png +++ /dev/null diff --git a/tests/ref/meta/counter-page.png b/tests/ref/meta/counter-page.png Binary files differdeleted file mode 100644 index 869718bc..00000000 --- a/tests/ref/meta/counter-page.png +++ /dev/null diff --git a/tests/ref/meta/counter.png b/tests/ref/meta/counter.png Binary files differdeleted file mode 100644 index 6c29ac17..00000000 --- a/tests/ref/meta/counter.png +++ /dev/null diff --git a/tests/ref/meta/document.png b/tests/ref/meta/document.png Binary files differdeleted file mode 100644 index 6db26511..00000000 --- a/tests/ref/meta/document.png +++ /dev/null diff --git a/tests/ref/meta/figure-caption.png b/tests/ref/meta/figure-caption.png Binary files differdeleted file mode 100644 index 8a1d4a59..00000000 --- a/tests/ref/meta/figure-caption.png +++ /dev/null diff --git a/tests/ref/meta/figure-localization.png b/tests/ref/meta/figure-localization.png Binary files differdeleted file mode 100644 index 5fcbd2b7..00000000 --- a/tests/ref/meta/figure-localization.png +++ /dev/null diff --git a/tests/ref/meta/figure.png b/tests/ref/meta/figure.png Binary files differdeleted file mode 100644 index bcdd0d2f..00000000 --- a/tests/ref/meta/figure.png +++ /dev/null diff --git a/tests/ref/meta/footnote-break.png b/tests/ref/meta/footnote-break.png Binary files differdeleted file mode 100644 index 625305c8..00000000 --- a/tests/ref/meta/footnote-break.png +++ /dev/null diff --git a/tests/ref/meta/footnote-columns.png b/tests/ref/meta/footnote-columns.png Binary files differdeleted file mode 100644 index 528ec664..00000000 --- a/tests/ref/meta/footnote-columns.png +++ /dev/null diff --git a/tests/ref/meta/footnote-container.png b/tests/ref/meta/footnote-container.png Binary files differdeleted file mode 100644 index 9327e7ee..00000000 --- a/tests/ref/meta/footnote-container.png +++ /dev/null diff --git a/tests/ref/meta/footnote-invariant.png b/tests/ref/meta/footnote-invariant.png Binary files differdeleted file mode 100644 index 66b41182..00000000 --- a/tests/ref/meta/footnote-invariant.png +++ /dev/null diff --git a/tests/ref/meta/footnote-refs.png b/tests/ref/meta/footnote-refs.png Binary files differdeleted file mode 100644 index 3fab7bd5..00000000 --- a/tests/ref/meta/footnote-refs.png +++ /dev/null diff --git a/tests/ref/meta/footnote-table.png b/tests/ref/meta/footnote-table.png Binary files differdeleted file mode 100644 index 023f8008..00000000 --- a/tests/ref/meta/footnote-table.png +++ /dev/null diff --git a/tests/ref/meta/footnote.png b/tests/ref/meta/footnote.png Binary files differdeleted file mode 100644 index 4c67bbd7..00000000 --- a/tests/ref/meta/footnote.png +++ /dev/null diff --git a/tests/ref/meta/heading.png b/tests/ref/meta/heading.png Binary files differdeleted file mode 100644 index 8467ea53..00000000 --- a/tests/ref/meta/heading.png +++ /dev/null diff --git a/tests/ref/meta/link.png b/tests/ref/meta/link.png Binary files differdeleted file mode 100644 index 3c3ecd2c..00000000 --- a/tests/ref/meta/link.png +++ /dev/null diff --git a/tests/ref/meta/numbering.png b/tests/ref/meta/numbering.png Binary files differdeleted file mode 100644 index fa5b520f..00000000 --- a/tests/ref/meta/numbering.png +++ /dev/null diff --git a/tests/ref/meta/outline-entry.png b/tests/ref/meta/outline-entry.png Binary files differdeleted file mode 100644 index f8f5412f..00000000 --- a/tests/ref/meta/outline-entry.png +++ /dev/null diff --git a/tests/ref/meta/outline-first-par-indent.png b/tests/ref/meta/outline-first-par-indent.png Binary files differdeleted file mode 100644 index f6e4ffe8..00000000 --- a/tests/ref/meta/outline-first-par-indent.png +++ /dev/null diff --git a/tests/ref/meta/outline-indent.png b/tests/ref/meta/outline-indent.png Binary files differdeleted file mode 100644 index 816d86a5..00000000 --- a/tests/ref/meta/outline-indent.png +++ /dev/null diff --git a/tests/ref/meta/outline.png b/tests/ref/meta/outline.png Binary files differdeleted file mode 100644 index 047bcc80..00000000 --- a/tests/ref/meta/outline.png +++ /dev/null diff --git a/tests/ref/meta/page-label.png b/tests/ref/meta/page-label.png Binary files differdeleted file mode 100644 index 301d626a..00000000 --- a/tests/ref/meta/page-label.png +++ /dev/null diff --git a/tests/ref/meta/query-before-after.png b/tests/ref/meta/query-before-after.png Binary files differdeleted file mode 100644 index 80f8fe1f..00000000 --- a/tests/ref/meta/query-before-after.png +++ /dev/null diff --git a/tests/ref/meta/query-figure.png b/tests/ref/meta/query-figure.png Binary files differdeleted file mode 100644 index 2537ebf0..00000000 --- a/tests/ref/meta/query-figure.png +++ /dev/null diff --git a/tests/ref/meta/query-header.png b/tests/ref/meta/query-header.png Binary files differdeleted file mode 100644 index c2dc4689..00000000 --- a/tests/ref/meta/query-header.png +++ /dev/null diff --git a/tests/ref/meta/ref.png b/tests/ref/meta/ref.png Binary files differdeleted file mode 100644 index 51563f54..00000000 --- a/tests/ref/meta/ref.png +++ /dev/null diff --git a/tests/ref/meta/state.png b/tests/ref/meta/state.png Binary files differdeleted file mode 100644 index 25faa0d9..00000000 --- a/tests/ref/meta/state.png +++ /dev/null diff --git a/tests/ref/newline-continuation-code.png b/tests/ref/newline-continuation-code.png Binary files differnew file mode 100644 index 00000000..46a6afd5 --- /dev/null +++ b/tests/ref/newline-continuation-code.png diff --git a/tests/ref/newline-continuation-markup.png b/tests/ref/newline-continuation-markup.png Binary files differnew file mode 100644 index 00000000..268e5f84 --- /dev/null +++ b/tests/ref/newline-continuation-markup.png diff --git a/tests/ref/numbering-chinese.png b/tests/ref/numbering-chinese.png Binary files differnew file mode 100644 index 00000000..06b31334 --- /dev/null +++ b/tests/ref/numbering-chinese.png diff --git a/tests/ref/numbering-hebrew.png b/tests/ref/numbering-hebrew.png Binary files differnew file mode 100644 index 00000000..d7614225 --- /dev/null +++ b/tests/ref/numbering-hebrew.png diff --git a/tests/ref/numbering-japanese-aiueo.png b/tests/ref/numbering-japanese-aiueo.png Binary files differnew file mode 100644 index 00000000..b06d5c69 --- /dev/null +++ b/tests/ref/numbering-japanese-aiueo.png diff --git a/tests/ref/numbering-japanese-iroha.png b/tests/ref/numbering-japanese-iroha.png Binary files differnew file mode 100644 index 00000000..2018802f --- /dev/null +++ b/tests/ref/numbering-japanese-iroha.png diff --git a/tests/ref/numbering-korean.png b/tests/ref/numbering-korean.png Binary files differnew file mode 100644 index 00000000..281f2ec2 --- /dev/null +++ b/tests/ref/numbering-korean.png diff --git a/tests/ref/numbering-latin.png b/tests/ref/numbering-latin.png Binary files differnew file mode 100644 index 00000000..e154735a --- /dev/null +++ b/tests/ref/numbering-latin.png diff --git a/tests/ref/numbering-symbol-and-roman.png b/tests/ref/numbering-symbol-and-roman.png Binary files differnew file mode 100644 index 00000000..979f3b90 --- /dev/null +++ b/tests/ref/numbering-symbol-and-roman.png diff --git a/tests/ref/numbers.png b/tests/ref/numbers.png Binary files differnew file mode 100644 index 00000000..e6e7215b --- /dev/null +++ b/tests/ref/numbers.png diff --git a/tests/ref/ops-add-content.png b/tests/ref/ops-add-content.png Binary files differnew file mode 100644 index 00000000..bdb8cb5e --- /dev/null +++ b/tests/ref/ops-add-content.png diff --git a/tests/ref/ops-multiply-inf-with-length.png b/tests/ref/ops-multiply-inf-with-length.png Binary files differnew file mode 100644 index 00000000..749be056 --- /dev/null +++ b/tests/ref/ops-multiply-inf-with-length.png diff --git a/tests/ref/outline-entry-complex.png b/tests/ref/outline-entry-complex.png Binary files differnew file mode 100644 index 00000000..c885cacc --- /dev/null +++ b/tests/ref/outline-entry-complex.png diff --git a/tests/ref/outline-entry.png b/tests/ref/outline-entry.png Binary files differnew file mode 100644 index 00000000..94e7a5a7 --- /dev/null +++ b/tests/ref/outline-entry.png diff --git a/tests/ref/outline-first-line-indent.png b/tests/ref/outline-first-line-indent.png Binary files differnew file mode 100644 index 00000000..dd995f31 --- /dev/null +++ b/tests/ref/outline-first-line-indent.png diff --git a/tests/ref/outline-indent-no-numbering.png b/tests/ref/outline-indent-no-numbering.png Binary files differnew file mode 100644 index 00000000..62bd80a3 --- /dev/null +++ b/tests/ref/outline-indent-no-numbering.png diff --git a/tests/ref/outline-indent-numbering.png b/tests/ref/outline-indent-numbering.png Binary files differnew file mode 100644 index 00000000..6c936827 --- /dev/null +++ b/tests/ref/outline-indent-numbering.png diff --git a/tests/ref/outline.png b/tests/ref/outline.png Binary files differnew file mode 100644 index 00000000..e5c24a98 --- /dev/null +++ b/tests/ref/outline.png diff --git a/tests/ref/overhang-lone.png b/tests/ref/overhang-lone.png Binary files differnew file mode 100644 index 00000000..b48618fb --- /dev/null +++ b/tests/ref/overhang-lone.png diff --git a/tests/ref/overhang.png b/tests/ref/overhang.png Binary files differnew file mode 100644 index 00000000..b97ef30c --- /dev/null +++ b/tests/ref/overhang.png diff --git a/tests/ref/overline-background.png b/tests/ref/overline-background.png Binary files differnew file mode 100644 index 00000000..8efd147e --- /dev/null +++ b/tests/ref/overline-background.png diff --git a/tests/ref/pad-basic.png b/tests/ref/pad-basic.png Binary files differnew file mode 100644 index 00000000..f8c40088 --- /dev/null +++ b/tests/ref/pad-basic.png diff --git a/tests/ref/pad-expanding-contents.png b/tests/ref/pad-expanding-contents.png Binary files differnew file mode 100644 index 00000000..1bef4a81 --- /dev/null +++ b/tests/ref/pad-expanding-contents.png diff --git a/tests/ref/pad-followed-by-content.png b/tests/ref/pad-followed-by-content.png Binary files differnew file mode 100644 index 00000000..f0f06a6c --- /dev/null +++ b/tests/ref/pad-followed-by-content.png diff --git a/tests/ref/page-call-followed-by-pagebreak.png b/tests/ref/page-call-followed-by-pagebreak.png Binary files differnew file mode 100644 index 00000000..87cd9735 --- /dev/null +++ b/tests/ref/page-call-followed-by-pagebreak.png diff --git a/tests/ref/page-call-styled-empty.png b/tests/ref/page-call-styled-empty.png Binary files differnew file mode 100644 index 00000000..6a24b1bc --- /dev/null +++ b/tests/ref/page-call-styled-empty.png diff --git a/tests/ref/page-fill.png b/tests/ref/page-fill.png Binary files differnew file mode 100644 index 00000000..0c7ab277 --- /dev/null +++ b/tests/ref/page-fill.png diff --git a/tests/ref/page-large.png b/tests/ref/page-large.png Binary files differnew file mode 100644 index 00000000..a57dceec --- /dev/null +++ b/tests/ref/page-large.png diff --git a/tests/ref/page-margin-binding-from-text-lang.png b/tests/ref/page-margin-binding-from-text-lang.png Binary files differnew file mode 100644 index 00000000..8d12ff2f --- /dev/null +++ b/tests/ref/page-margin-binding-from-text-lang.png diff --git a/tests/ref/page-margin-individual.png b/tests/ref/page-margin-individual.png Binary files differnew file mode 100644 index 00000000..0bc0f51b --- /dev/null +++ b/tests/ref/page-margin-individual.png diff --git a/tests/ref/page-margin-inside-outside-override.png b/tests/ref/page-margin-inside-outside-override.png Binary files differnew file mode 100644 index 00000000..5aa8bf12 --- /dev/null +++ b/tests/ref/page-margin-inside-outside-override.png diff --git a/tests/ref/page-margin-inside-with-binding.png b/tests/ref/page-margin-inside-with-binding.png Binary files differnew file mode 100644 index 00000000..5b9ec04f --- /dev/null +++ b/tests/ref/page-margin-inside-with-binding.png diff --git a/tests/ref/page-margin-inside.png b/tests/ref/page-margin-inside.png Binary files differnew file mode 100644 index 00000000..d70b8604 --- /dev/null +++ b/tests/ref/page-margin-inside.png diff --git a/tests/ref/page-margin-uniform.png b/tests/ref/page-margin-uniform.png Binary files differnew file mode 100644 index 00000000..8a06fb74 --- /dev/null +++ b/tests/ref/page-margin-uniform.png diff --git a/tests/ref/page-marginals.png b/tests/ref/page-marginals.png Binary files differnew file mode 100644 index 00000000..cab886b3 --- /dev/null +++ b/tests/ref/page-marginals.png diff --git a/tests/ref/page-number-align-bottom-left.png b/tests/ref/page-number-align-bottom-left.png Binary files differnew file mode 100644 index 00000000..396f6e98 --- /dev/null +++ b/tests/ref/page-number-align-bottom-left.png diff --git a/tests/ref/page-number-align-top-right.png b/tests/ref/page-number-align-top-right.png Binary files differnew file mode 100644 index 00000000..3c7e5579 --- /dev/null +++ b/tests/ref/page-number-align-top-right.png diff --git a/tests/ref/page-numbering-pdf-label.png b/tests/ref/page-numbering-pdf-label.png Binary files differnew file mode 100644 index 00000000..a1cae720 --- /dev/null +++ b/tests/ref/page-numbering-pdf-label.png diff --git a/tests/ref/page-set-empty.png b/tests/ref/page-set-empty.png Binary files differnew file mode 100644 index 00000000..6a24b1bc --- /dev/null +++ b/tests/ref/page-set-empty.png diff --git a/tests/ref/page-set-forces-break.png b/tests/ref/page-set-forces-break.png Binary files differnew file mode 100644 index 00000000..4654ef6c --- /dev/null +++ b/tests/ref/page-set-forces-break.png diff --git a/tests/ref/page-set-only-pagebreak.png b/tests/ref/page-set-only-pagebreak.png Binary files differnew file mode 100644 index 00000000..9bf379d6 --- /dev/null +++ b/tests/ref/page-set-only-pagebreak.png diff --git a/tests/ref/page-set-override-and-mix.png b/tests/ref/page-set-override-and-mix.png Binary files differnew file mode 100644 index 00000000..d9df6acd --- /dev/null +++ b/tests/ref/page-set-override-and-mix.png diff --git a/tests/ref/page-set-override-thrice.png b/tests/ref/page-set-override-thrice.png Binary files differnew file mode 100644 index 00000000..99173ced --- /dev/null +++ b/tests/ref/page-set-override-thrice.png diff --git a/tests/ref/pagebreak-around-set-page.png b/tests/ref/pagebreak-around-set-page.png Binary files differnew file mode 100644 index 00000000..2c1ce508 --- /dev/null +++ b/tests/ref/pagebreak-around-set-page.png diff --git a/tests/ref/pagebreak-followed-by-page-call.png b/tests/ref/pagebreak-followed-by-page-call.png Binary files differnew file mode 100644 index 00000000..ee435cdc --- /dev/null +++ b/tests/ref/pagebreak-followed-by-page-call.png diff --git a/tests/ref/pagebreak-meta.png b/tests/ref/pagebreak-meta.png Binary files differnew file mode 100644 index 00000000..7953dc51 --- /dev/null +++ b/tests/ref/pagebreak-meta.png diff --git a/tests/ref/pagebreak-set-page-mixed.png b/tests/ref/pagebreak-set-page-mixed.png Binary files differnew file mode 100644 index 00000000..3502ee42 --- /dev/null +++ b/tests/ref/pagebreak-set-page-mixed.png diff --git a/tests/ref/pagebreak-to-auto-sized.png b/tests/ref/pagebreak-to-auto-sized.png Binary files differnew file mode 100644 index 00000000..f3e2df45 --- /dev/null +++ b/tests/ref/pagebreak-to-auto-sized.png diff --git a/tests/ref/pagebreak-to-multiple-pages.png b/tests/ref/pagebreak-to-multiple-pages.png Binary files differnew file mode 100644 index 00000000..a7af0a9a --- /dev/null +++ b/tests/ref/pagebreak-to-multiple-pages.png diff --git a/tests/ref/pagebreak-to.png b/tests/ref/pagebreak-to.png Binary files differnew file mode 100644 index 00000000..62a4ee20 --- /dev/null +++ b/tests/ref/pagebreak-to.png diff --git a/tests/ref/pagebreak-weak-after-set-page.png b/tests/ref/pagebreak-weak-after-set-page.png Binary files differnew file mode 100644 index 00000000..c8014df1 --- /dev/null +++ b/tests/ref/pagebreak-weak-after-set-page.png diff --git a/tests/ref/pagebreak-weak-meta.png b/tests/ref/pagebreak-weak-meta.png Binary files differnew file mode 100644 index 00000000..aa69e606 --- /dev/null +++ b/tests/ref/pagebreak-weak-meta.png diff --git a/tests/ref/pagebreak-weak-place.png b/tests/ref/pagebreak-weak-place.png Binary files differnew file mode 100644 index 00000000..f85bdf02 --- /dev/null +++ b/tests/ref/pagebreak-weak-place.png diff --git a/tests/ref/pagebreak.png b/tests/ref/pagebreak.png Binary files differnew file mode 100644 index 00000000..d07473d9 --- /dev/null +++ b/tests/ref/pagebreak.png diff --git a/tests/ref/par-basic.png b/tests/ref/par-basic.png Binary files differnew file mode 100644 index 00000000..ffd9de9a --- /dev/null +++ b/tests/ref/par-basic.png diff --git a/tests/ref/par-first-line-indent.png b/tests/ref/par-first-line-indent.png Binary files differnew file mode 100644 index 00000000..e6d7ed76 --- /dev/null +++ b/tests/ref/par-first-line-indent.png diff --git a/tests/ref/par-hanging-indent-manual-linebreak.png b/tests/ref/par-hanging-indent-manual-linebreak.png Binary files differnew file mode 100644 index 00000000..e9c666cd --- /dev/null +++ b/tests/ref/par-hanging-indent-manual-linebreak.png diff --git a/tests/ref/par-hanging-indent-rtl.png b/tests/ref/par-hanging-indent-rtl.png Binary files differnew file mode 100644 index 00000000..849e0a01 --- /dev/null +++ b/tests/ref/par-hanging-indent-rtl.png diff --git a/tests/ref/par-hanging-indent.png b/tests/ref/par-hanging-indent.png Binary files differnew file mode 100644 index 00000000..49455a78 --- /dev/null +++ b/tests/ref/par-hanging-indent.png diff --git a/tests/ref/par-leading-and-block-spacing.png b/tests/ref/par-leading-and-block-spacing.png Binary files differnew file mode 100644 index 00000000..faaa3116 --- /dev/null +++ b/tests/ref/par-leading-and-block-spacing.png diff --git a/tests/ref/par-spacing-and-first-line-indent.png b/tests/ref/par-spacing-and-first-line-indent.png Binary files differnew file mode 100644 index 00000000..c322f630 --- /dev/null +++ b/tests/ref/par-spacing-and-first-line-indent.png diff --git a/tests/ref/parser-backtracking-destructuring-whitespace.png b/tests/ref/parser-backtracking-destructuring-whitespace.png Binary files differnew file mode 100644 index 00000000..d5d72888 --- /dev/null +++ b/tests/ref/parser-backtracking-destructuring-whitespace.png diff --git a/tests/ref/path.png b/tests/ref/path.png Binary files differnew file mode 100644 index 00000000..9643a476 --- /dev/null +++ b/tests/ref/path.png diff --git a/tests/ref/pattern-line.png b/tests/ref/pattern-line.png Binary files differnew file mode 100644 index 00000000..b891b6d7 --- /dev/null +++ b/tests/ref/pattern-line.png diff --git a/tests/ref/pattern-lines.png b/tests/ref/pattern-lines.png Binary files differnew file mode 100644 index 00000000..008d357e --- /dev/null +++ b/tests/ref/pattern-lines.png diff --git a/tests/ref/pattern-relative-parent.png b/tests/ref/pattern-relative-parent.png Binary files differnew file mode 100644 index 00000000..786057ef --- /dev/null +++ b/tests/ref/pattern-relative-parent.png diff --git a/tests/ref/pattern-relative-self.png b/tests/ref/pattern-relative-self.png Binary files differnew file mode 100644 index 00000000..28408081 --- /dev/null +++ b/tests/ref/pattern-relative-self.png diff --git a/tests/ref/pattern-small.png b/tests/ref/pattern-small.png Binary files differnew file mode 100644 index 00000000..0406252d --- /dev/null +++ b/tests/ref/pattern-small.png diff --git a/tests/ref/pattern-spacing-negative.png b/tests/ref/pattern-spacing-negative.png Binary files differnew file mode 100644 index 00000000..659c2283 --- /dev/null +++ b/tests/ref/pattern-spacing-negative.png diff --git a/tests/ref/pattern-spacing-positive.png b/tests/ref/pattern-spacing-positive.png Binary files differnew file mode 100644 index 00000000..3e475eee --- /dev/null +++ b/tests/ref/pattern-spacing-positive.png diff --git a/tests/ref/pattern-spacing-zero.png b/tests/ref/pattern-spacing-zero.png Binary files differnew file mode 100644 index 00000000..5118471a --- /dev/null +++ b/tests/ref/pattern-spacing-zero.png diff --git a/tests/ref/pattern-stroke.png b/tests/ref/pattern-stroke.png Binary files differnew file mode 100644 index 00000000..8b03783b --- /dev/null +++ b/tests/ref/pattern-stroke.png diff --git a/tests/ref/pattern-text.png b/tests/ref/pattern-text.png Binary files differnew file mode 100644 index 00000000..de9bfc2e --- /dev/null +++ b/tests/ref/pattern-text.png diff --git a/tests/ref/place-background.png b/tests/ref/place-background.png Binary files differnew file mode 100644 index 00000000..7d732717 --- /dev/null +++ b/tests/ref/place-background.png diff --git a/tests/ref/place-basic.png b/tests/ref/place-basic.png Binary files differnew file mode 100644 index 00000000..07642c34 --- /dev/null +++ b/tests/ref/place-basic.png diff --git a/tests/ref/place-block-spacing.png b/tests/ref/place-block-spacing.png Binary files differnew file mode 100644 index 00000000..fb01d1b6 --- /dev/null +++ b/tests/ref/place-block-spacing.png diff --git a/tests/ref/place-bottom-in-box.png b/tests/ref/place-bottom-in-box.png Binary files differnew file mode 100644 index 00000000..fdd8c010 --- /dev/null +++ b/tests/ref/place-bottom-in-box.png diff --git a/tests/ref/place-bottom-right-in-box.png b/tests/ref/place-bottom-right-in-box.png Binary files differnew file mode 100644 index 00000000..49c40886 --- /dev/null +++ b/tests/ref/place-bottom-right-in-box.png diff --git a/tests/ref/place-float-columns.png b/tests/ref/place-float-columns.png Binary files differnew file mode 100644 index 00000000..97065b68 --- /dev/null +++ b/tests/ref/place-float-columns.png diff --git a/tests/ref/place-float-figure.png b/tests/ref/place-float-figure.png Binary files differnew file mode 100644 index 00000000..5411178a --- /dev/null +++ b/tests/ref/place-float-figure.png diff --git a/tests/ref/place-float.png b/tests/ref/place-float.png Binary files differnew file mode 100644 index 00000000..ddd49c47 --- /dev/null +++ b/tests/ref/place-float.png diff --git a/tests/ref/place-horizon-in-boxes.png b/tests/ref/place-horizon-in-boxes.png Binary files differnew file mode 100644 index 00000000..b6d333bf --- /dev/null +++ b/tests/ref/place-horizon-in-boxes.png diff --git a/tests/ref/place-top-left-in-box.png b/tests/ref/place-top-left-in-box.png Binary files differnew file mode 100644 index 00000000..914ffa58 --- /dev/null +++ b/tests/ref/place-top-left-in-box.png diff --git a/tests/ref/polygon-line-join.png b/tests/ref/polygon-line-join.png Binary files differnew file mode 100644 index 00000000..0f65fa70 --- /dev/null +++ b/tests/ref/polygon-line-join.png diff --git a/tests/ref/polygon.png b/tests/ref/polygon.png Binary files differnew file mode 100644 index 00000000..1dc11083 --- /dev/null +++ b/tests/ref/polygon.png diff --git a/tests/ref/query-and-or.png b/tests/ref/query-and-or.png Binary files differnew file mode 100644 index 00000000..39cfd076 --- /dev/null +++ b/tests/ref/query-and-or.png diff --git a/tests/ref/query-before-after.png b/tests/ref/query-before-after.png Binary files differnew file mode 100644 index 00000000..33fde985 --- /dev/null +++ b/tests/ref/query-before-after.png diff --git a/tests/ref/query-complex.png b/tests/ref/query-complex.png Binary files differnew file mode 100644 index 00000000..f71dcce5 --- /dev/null +++ b/tests/ref/query-complex.png diff --git a/tests/ref/query-list-of-figures.png b/tests/ref/query-list-of-figures.png Binary files differnew file mode 100644 index 00000000..c94ccd00 --- /dev/null +++ b/tests/ref/query-list-of-figures.png diff --git a/tests/ref/query-running-header.png b/tests/ref/query-running-header.png Binary files differnew file mode 100644 index 00000000..210c7810 --- /dev/null +++ b/tests/ref/query-running-header.png diff --git a/tests/ref/quote-block-spacing.png b/tests/ref/quote-block-spacing.png Binary files differnew file mode 100644 index 00000000..3efae5ab --- /dev/null +++ b/tests/ref/quote-block-spacing.png diff --git a/tests/ref/quote-cite-format-author-date.png b/tests/ref/quote-cite-format-author-date.png Binary files differnew file mode 100644 index 00000000..43816f8c --- /dev/null +++ b/tests/ref/quote-cite-format-author-date.png diff --git a/tests/ref/quote-cite-format-label-or-numeric.png b/tests/ref/quote-cite-format-label-or-numeric.png Binary files differnew file mode 100644 index 00000000..f0f5f90f --- /dev/null +++ b/tests/ref/quote-cite-format-label-or-numeric.png diff --git a/tests/ref/quote-cite-format-note.png b/tests/ref/quote-cite-format-note.png Binary files differnew file mode 100644 index 00000000..1092ffdb --- /dev/null +++ b/tests/ref/quote-cite-format-note.png diff --git a/tests/ref/quote-dir-align.png b/tests/ref/quote-dir-align.png Binary files differnew file mode 100644 index 00000000..0341f87c --- /dev/null +++ b/tests/ref/quote-dir-align.png diff --git a/tests/ref/quote-dir-author-pos.png b/tests/ref/quote-dir-author-pos.png Binary files differnew file mode 100644 index 00000000..842796a2 --- /dev/null +++ b/tests/ref/quote-dir-author-pos.png diff --git a/tests/ref/quote-inline.png b/tests/ref/quote-inline.png Binary files differnew file mode 100644 index 00000000..4dbc9720 --- /dev/null +++ b/tests/ref/quote-inline.png diff --git a/tests/ref/quote-nesting-custom.png b/tests/ref/quote-nesting-custom.png Binary files differnew file mode 100644 index 00000000..e26b6258 --- /dev/null +++ b/tests/ref/quote-nesting-custom.png diff --git a/tests/ref/quote-nesting.png b/tests/ref/quote-nesting.png Binary files differnew file mode 100644 index 00000000..dcd1e378 --- /dev/null +++ b/tests/ref/quote-nesting.png diff --git a/tests/ref/raw-align-default.png b/tests/ref/raw-align-default.png Binary files differnew file mode 100644 index 00000000..84c51229 --- /dev/null +++ b/tests/ref/raw-align-default.png diff --git a/tests/ref/raw-align-specified.png b/tests/ref/raw-align-specified.png Binary files differnew file mode 100644 index 00000000..18b48dec --- /dev/null +++ b/tests/ref/raw-align-specified.png diff --git a/tests/ref/raw-block-no-parbreaks.png b/tests/ref/raw-block-no-parbreaks.png Binary files differnew file mode 100644 index 00000000..401cc5a9 --- /dev/null +++ b/tests/ref/raw-block-no-parbreaks.png diff --git a/tests/ref/raw-consecutive-single-backticks.png b/tests/ref/raw-consecutive-single-backticks.png Binary files differnew file mode 100644 index 00000000..159d0eda --- /dev/null +++ b/tests/ref/raw-consecutive-single-backticks.png diff --git a/tests/ref/raw-dedent-empty-line.png b/tests/ref/raw-dedent-empty-line.png Binary files differnew file mode 100644 index 00000000..c3c88e7a --- /dev/null +++ b/tests/ref/raw-dedent-empty-line.png diff --git a/tests/ref/raw-dedent-first-line.png b/tests/ref/raw-dedent-first-line.png Binary files differnew file mode 100644 index 00000000..c6eee5ce --- /dev/null +++ b/tests/ref/raw-dedent-first-line.png diff --git a/tests/ref/raw-dedent-last-line.png b/tests/ref/raw-dedent-last-line.png Binary files differnew file mode 100644 index 00000000..2b1fe747 --- /dev/null +++ b/tests/ref/raw-dedent-last-line.png diff --git a/tests/ref/raw-empty.png b/tests/ref/raw-empty.png Binary files differnew file mode 100644 index 00000000..a47eb855 --- /dev/null +++ b/tests/ref/raw-empty.png diff --git a/tests/ref/raw-highlight-typ.png b/tests/ref/raw-highlight-typ.png Binary files differnew file mode 100644 index 00000000..f80bbf89 --- /dev/null +++ b/tests/ref/raw-highlight-typ.png diff --git a/tests/ref/raw-highlight.png b/tests/ref/raw-highlight.png Binary files differnew file mode 100644 index 00000000..2f99b450 --- /dev/null +++ b/tests/ref/raw-highlight.png diff --git a/tests/ref/raw-inline-multiline.png b/tests/ref/raw-inline-multiline.png Binary files differnew file mode 100644 index 00000000..7db3126d --- /dev/null +++ b/tests/ref/raw-inline-multiline.png diff --git a/tests/ref/raw-line-alternating-fill.png b/tests/ref/raw-line-alternating-fill.png Binary files differnew file mode 100644 index 00000000..b8053129 --- /dev/null +++ b/tests/ref/raw-line-alternating-fill.png diff --git a/tests/ref/raw-line-text-fill.png b/tests/ref/raw-line-text-fill.png Binary files differnew file mode 100644 index 00000000..5b3c4d19 --- /dev/null +++ b/tests/ref/raw-line-text-fill.png diff --git a/tests/ref/raw-line.png b/tests/ref/raw-line.png Binary files differnew file mode 100644 index 00000000..c8ada95d --- /dev/null +++ b/tests/ref/raw-line.png diff --git a/tests/ref/raw-more-backticks.png b/tests/ref/raw-more-backticks.png Binary files differnew file mode 100644 index 00000000..ab836011 --- /dev/null +++ b/tests/ref/raw-more-backticks.png diff --git a/tests/ref/raw-show-set.png b/tests/ref/raw-show-set.png Binary files differnew file mode 100644 index 00000000..8a82c2e9 --- /dev/null +++ b/tests/ref/raw-show-set.png diff --git a/tests/ref/raw-single-backtick-lang.png b/tests/ref/raw-single-backtick-lang.png Binary files differnew file mode 100644 index 00000000..b420627e --- /dev/null +++ b/tests/ref/raw-single-backtick-lang.png diff --git a/tests/ref/raw-syntaxes.png b/tests/ref/raw-syntaxes.png Binary files differnew file mode 100644 index 00000000..4e14cd06 --- /dev/null +++ b/tests/ref/raw-syntaxes.png diff --git a/tests/ref/raw-tab-size.png b/tests/ref/raw-tab-size.png Binary files differnew file mode 100644 index 00000000..132a10b3 --- /dev/null +++ b/tests/ref/raw-tab-size.png diff --git a/tests/ref/raw-theme.png b/tests/ref/raw-theme.png Binary files differnew file mode 100644 index 00000000..78561ac6 --- /dev/null +++ b/tests/ref/raw-theme.png diff --git a/tests/ref/raw-trimming.png b/tests/ref/raw-trimming.png Binary files differnew file mode 100644 index 00000000..58d90b7f --- /dev/null +++ b/tests/ref/raw-trimming.png diff --git a/tests/ref/raw-typst-lang.png b/tests/ref/raw-typst-lang.png Binary files differnew file mode 100644 index 00000000..3dcafafb --- /dev/null +++ b/tests/ref/raw-typst-lang.png diff --git a/tests/ref/rect-customization.png b/tests/ref/rect-customization.png Binary files differnew file mode 100644 index 00000000..93808920 --- /dev/null +++ b/tests/ref/rect-customization.png diff --git a/tests/ref/rect-fill-stroke.png b/tests/ref/rect-fill-stroke.png Binary files differnew file mode 100644 index 00000000..28a47c12 --- /dev/null +++ b/tests/ref/rect-fill-stroke.png diff --git a/tests/ref/rect-stroke.png b/tests/ref/rect-stroke.png Binary files differnew file mode 100644 index 00000000..7d59c049 --- /dev/null +++ b/tests/ref/rect-stroke.png diff --git a/tests/ref/rect.png b/tests/ref/rect.png Binary files differnew file mode 100644 index 00000000..04e435ed --- /dev/null +++ b/tests/ref/rect.png diff --git a/tests/ref/ref-basic.png b/tests/ref/ref-basic.png Binary files differnew file mode 100644 index 00000000..94d94789 --- /dev/null +++ b/tests/ref/ref-basic.png diff --git a/tests/ref/ref-supplements.png b/tests/ref/ref-supplements.png Binary files differnew file mode 100644 index 00000000..46d1524a --- /dev/null +++ b/tests/ref/ref-supplements.png diff --git a/tests/ref/repeat-align-and-dir.png b/tests/ref/repeat-align-and-dir.png Binary files differnew file mode 100644 index 00000000..16797d04 --- /dev/null +++ b/tests/ref/repeat-align-and-dir.png diff --git a/tests/ref/repeat-basic.png b/tests/ref/repeat-basic.png Binary files differnew file mode 100644 index 00000000..61e7f50f --- /dev/null +++ b/tests/ref/repeat-basic.png diff --git a/tests/ref/repeat-dots-rtl.png b/tests/ref/repeat-dots-rtl.png Binary files differnew file mode 100644 index 00000000..a0f1a919 --- /dev/null +++ b/tests/ref/repeat-dots-rtl.png diff --git a/tests/ref/repeat-empty.png b/tests/ref/repeat-empty.png Binary files differnew file mode 100644 index 00000000..c23d7fa4 --- /dev/null +++ b/tests/ref/repeat-empty.png diff --git a/tests/ref/repeat-unboxed.png b/tests/ref/repeat-unboxed.png Binary files differnew file mode 100644 index 00000000..91678cea --- /dev/null +++ b/tests/ref/repeat-unboxed.png diff --git a/tests/ref/repr-color.png b/tests/ref/repr-color.png Binary files differnew file mode 100644 index 00000000..3425f7d4 --- /dev/null +++ b/tests/ref/repr-color.png diff --git a/tests/ref/repr-literals.png b/tests/ref/repr-literals.png Binary files differnew file mode 100644 index 00000000..1e8e85a4 --- /dev/null +++ b/tests/ref/repr-literals.png diff --git a/tests/ref/repr-misc.png b/tests/ref/repr-misc.png Binary files differnew file mode 100644 index 00000000..f4ac7c5f --- /dev/null +++ b/tests/ref/repr-misc.png diff --git a/tests/ref/repr-numerical.png b/tests/ref/repr-numerical.png Binary files differnew file mode 100644 index 00000000..f1a6fe8e --- /dev/null +++ b/tests/ref/repr-numerical.png diff --git a/tests/ref/return-in-nested-content-block.png b/tests/ref/return-in-nested-content-block.png Binary files differnew file mode 100644 index 00000000..d688741c --- /dev/null +++ b/tests/ref/return-in-nested-content-block.png diff --git a/tests/ref/set-if.png b/tests/ref/set-if.png Binary files differnew file mode 100644 index 00000000..08dc5e82 --- /dev/null +++ b/tests/ref/set-if.png diff --git a/tests/ref/set-instantiation-site-markup.png b/tests/ref/set-instantiation-site-markup.png Binary files differnew file mode 100644 index 00000000..180444b9 --- /dev/null +++ b/tests/ref/set-instantiation-site-markup.png diff --git a/tests/ref/set-instantiation-site.png b/tests/ref/set-instantiation-site.png Binary files differnew file mode 100644 index 00000000..593d3e2d --- /dev/null +++ b/tests/ref/set-instantiation-site.png diff --git a/tests/ref/set-scoped-in-code-block.png b/tests/ref/set-scoped-in-code-block.png Binary files differnew file mode 100644 index 00000000..8941f6c4 --- /dev/null +++ b/tests/ref/set-scoped-in-code-block.png diff --git a/tests/ref/set-text-override.png b/tests/ref/set-text-override.png Binary files differnew file mode 100644 index 00000000..83623876 --- /dev/null +++ b/tests/ref/set-text-override.png diff --git a/tests/ref/set-vs-construct-1.png b/tests/ref/set-vs-construct-1.png Binary files differnew file mode 100644 index 00000000..597e9674 --- /dev/null +++ b/tests/ref/set-vs-construct-1.png diff --git a/tests/ref/set-vs-construct-2.png b/tests/ref/set-vs-construct-2.png Binary files differnew file mode 100644 index 00000000..2fedd0b4 --- /dev/null +++ b/tests/ref/set-vs-construct-2.png diff --git a/tests/ref/set-vs-construct-3.png b/tests/ref/set-vs-construct-3.png Binary files differnew file mode 100644 index 00000000..dff0c8af --- /dev/null +++ b/tests/ref/set-vs-construct-3.png diff --git a/tests/ref/set-vs-construct-4.png b/tests/ref/set-vs-construct-4.png Binary files differnew file mode 100644 index 00000000..1f6834ef --- /dev/null +++ b/tests/ref/set-vs-construct-4.png diff --git a/tests/ref/shaping-emoji-bad-zwj.png b/tests/ref/shaping-emoji-bad-zwj.png Binary files differnew file mode 100644 index 00000000..544d64ee --- /dev/null +++ b/tests/ref/shaping-emoji-bad-zwj.png diff --git a/tests/ref/shaping-emoji-basic.png b/tests/ref/shaping-emoji-basic.png Binary files differnew file mode 100644 index 00000000..090ea611 --- /dev/null +++ b/tests/ref/shaping-emoji-basic.png diff --git a/tests/ref/shaping-font-fallback.png b/tests/ref/shaping-font-fallback.png Binary files differnew file mode 100644 index 00000000..813e3915 --- /dev/null +++ b/tests/ref/shaping-font-fallback.png diff --git a/tests/ref/shaping-forced-script-font-feature-enabled.png b/tests/ref/shaping-forced-script-font-feature-enabled.png Binary files differnew file mode 100644 index 00000000..0a10087a --- /dev/null +++ b/tests/ref/shaping-forced-script-font-feature-enabled.png diff --git a/tests/ref/shaping-forced-script-font-feature-inhibited.png b/tests/ref/shaping-forced-script-font-feature-inhibited.png Binary files differnew file mode 100644 index 00000000..77d8010e --- /dev/null +++ b/tests/ref/shaping-forced-script-font-feature-inhibited.png diff --git a/tests/ref/shaping-script-separation.png b/tests/ref/shaping-script-separation.png Binary files differnew file mode 100644 index 00000000..68170dd9 --- /dev/null +++ b/tests/ref/shaping-script-separation.png diff --git a/tests/ref/shorthand-dashes.png b/tests/ref/shorthand-dashes.png Binary files differnew file mode 100644 index 00000000..f8b4191f --- /dev/null +++ b/tests/ref/shorthand-dashes.png diff --git a/tests/ref/shorthand-ellipsis.png b/tests/ref/shorthand-ellipsis.png Binary files differnew file mode 100644 index 00000000..df9a9241 --- /dev/null +++ b/tests/ref/shorthand-ellipsis.png diff --git a/tests/ref/shorthand-nbsp-and-shy-hyphen.png b/tests/ref/shorthand-nbsp-and-shy-hyphen.png Binary files differnew file mode 100644 index 00000000..e8c81aaa --- /dev/null +++ b/tests/ref/shorthand-nbsp-and-shy-hyphen.png diff --git a/tests/ref/shorthand-nbsp-width.png b/tests/ref/shorthand-nbsp-width.png Binary files differnew file mode 100644 index 00000000..a92988cf --- /dev/null +++ b/tests/ref/shorthand-nbsp-width.png diff --git a/tests/ref/shorthands-math.png b/tests/ref/shorthands-math.png Binary files differnew file mode 100644 index 00000000..0514fa62 --- /dev/null +++ b/tests/ref/shorthands-math.png diff --git a/tests/ref/show-bare-basic.png b/tests/ref/show-bare-basic.png Binary files differnew file mode 100644 index 00000000..e389b506 --- /dev/null +++ b/tests/ref/show-bare-basic.png diff --git a/tests/ref/show-bare-content-block.png b/tests/ref/show-bare-content-block.png Binary files differnew file mode 100644 index 00000000..2631092b --- /dev/null +++ b/tests/ref/show-bare-content-block.png diff --git a/tests/ref/show-bare-replace-with-content.png b/tests/ref/show-bare-replace-with-content.png Binary files differnew file mode 100644 index 00000000..51e36a49 --- /dev/null +++ b/tests/ref/show-bare-replace-with-content.png diff --git a/tests/ref/show-bare-vs-set-text.png b/tests/ref/show-bare-vs-set-text.png Binary files differnew file mode 100644 index 00000000..b1e15d98 --- /dev/null +++ b/tests/ref/show-bare-vs-set-text.png diff --git a/tests/ref/show-function-order-with-set.png b/tests/ref/show-function-order-with-set.png Binary files differnew file mode 100644 index 00000000..a59f7274 --- /dev/null +++ b/tests/ref/show-function-order-with-set.png diff --git a/tests/ref/show-function-set-on-it.png b/tests/ref/show-function-set-on-it.png Binary files differnew file mode 100644 index 00000000..6c545e95 --- /dev/null +++ b/tests/ref/show-function-set-on-it.png diff --git a/tests/ref/show-in-show.png b/tests/ref/show-in-show.png Binary files differnew file mode 100644 index 00000000..65280ad7 --- /dev/null +++ b/tests/ref/show-in-show.png diff --git a/tests/ref/show-multiple-rules.png b/tests/ref/show-multiple-rules.png Binary files differnew file mode 100644 index 00000000..c92b6269 --- /dev/null +++ b/tests/ref/show-multiple-rules.png diff --git a/tests/ref/show-nested-scopes.png b/tests/ref/show-nested-scopes.png Binary files differnew file mode 100644 index 00000000..ac0a8125 --- /dev/null +++ b/tests/ref/show-nested-scopes.png diff --git a/tests/ref/show-recursive-identity.png b/tests/ref/show-recursive-identity.png Binary files differnew file mode 100644 index 00000000..6c545e95 --- /dev/null +++ b/tests/ref/show-recursive-identity.png diff --git a/tests/ref/show-recursive-multiple.png b/tests/ref/show-recursive-multiple.png Binary files differnew file mode 100644 index 00000000..b56b089c --- /dev/null +++ b/tests/ref/show-recursive-multiple.png diff --git a/tests/ref/show-rule-in-function.png b/tests/ref/show-rule-in-function.png Binary files differnew file mode 100644 index 00000000..97aa2845 --- /dev/null +++ b/tests/ref/show-rule-in-function.png diff --git a/tests/ref/show-selector-basic.png b/tests/ref/show-selector-basic.png Binary files differnew file mode 100644 index 00000000..870166d9 --- /dev/null +++ b/tests/ref/show-selector-basic.png diff --git a/tests/ref/show-selector-discard.png b/tests/ref/show-selector-discard.png Binary files differnew file mode 100644 index 00000000..13c9f0d6 --- /dev/null +++ b/tests/ref/show-selector-discard.png diff --git a/tests/ref/show-selector-element-or-label.png b/tests/ref/show-selector-element-or-label.png Binary files differnew file mode 100644 index 00000000..32cd992d --- /dev/null +++ b/tests/ref/show-selector-element-or-label.png diff --git a/tests/ref/show-selector-or-elements-with-set.png b/tests/ref/show-selector-or-elements-with-set.png Binary files differnew file mode 100644 index 00000000..f561cad8 --- /dev/null +++ b/tests/ref/show-selector-or-elements-with-set.png diff --git a/tests/ref/show-selector-realistic.png b/tests/ref/show-selector-realistic.png Binary files differnew file mode 100644 index 00000000..ae4f4a9a --- /dev/null +++ b/tests/ref/show-selector-realistic.png diff --git a/tests/ref/show-selector-replace-and-show-set.png b/tests/ref/show-selector-replace-and-show-set.png Binary files differnew file mode 100644 index 00000000..47a7ae33 --- /dev/null +++ b/tests/ref/show-selector-replace-and-show-set.png diff --git a/tests/ref/show-selector-replace.png b/tests/ref/show-selector-replace.png Binary files differnew file mode 100644 index 00000000..c00a88e8 --- /dev/null +++ b/tests/ref/show-selector-replace.png diff --git a/tests/ref/show-selector-where.png b/tests/ref/show-selector-where.png Binary files differnew file mode 100644 index 00000000..4cb02efd --- /dev/null +++ b/tests/ref/show-selector-where.png diff --git a/tests/ref/show-set-on-layoutable-element.png b/tests/ref/show-set-on-layoutable-element.png Binary files differnew file mode 100644 index 00000000..701bea50 --- /dev/null +++ b/tests/ref/show-set-on-layoutable-element.png diff --git a/tests/ref/show-set-on-same-element.png b/tests/ref/show-set-on-same-element.png Binary files differnew file mode 100644 index 00000000..9459fca0 --- /dev/null +++ b/tests/ref/show-set-on-same-element.png diff --git a/tests/ref/show-set-override.png b/tests/ref/show-set-override.png Binary files differnew file mode 100644 index 00000000..e7831b90 --- /dev/null +++ b/tests/ref/show-set-override.png diff --git a/tests/ref/show-set-same-element-and-order.png b/tests/ref/show-set-same-element-and-order.png Binary files differnew file mode 100644 index 00000000..d55d5e14 --- /dev/null +++ b/tests/ref/show-set-same-element-and-order.png diff --git a/tests/ref/show-set-same-element-matched-field.png b/tests/ref/show-set-same-element-matched-field.png Binary files differnew file mode 100644 index 00000000..aa44baee --- /dev/null +++ b/tests/ref/show-set-same-element-matched-field.png diff --git a/tests/ref/show-set-same-element-matching-interaction.png b/tests/ref/show-set-same-element-matching-interaction.png Binary files differnew file mode 100644 index 00000000..bc061038 --- /dev/null +++ b/tests/ref/show-set-same-element-matching-interaction.png diff --git a/tests/ref/show-set-same-element-synthesized-matched-field.png b/tests/ref/show-set-same-element-synthesized-matched-field.png Binary files differnew file mode 100644 index 00000000..c3918e8f --- /dev/null +++ b/tests/ref/show-set-same-element-synthesized-matched-field.png diff --git a/tests/ref/show-set-text-order-adjacent-1.png b/tests/ref/show-set-text-order-adjacent-1.png Binary files differnew file mode 100644 index 00000000..1bc95e3b --- /dev/null +++ b/tests/ref/show-set-text-order-adjacent-1.png diff --git a/tests/ref/show-set-text-order-adjacent-2.png b/tests/ref/show-set-text-order-adjacent-2.png Binary files differnew file mode 100644 index 00000000..caada91a --- /dev/null +++ b/tests/ref/show-set-text-order-adjacent-2.png diff --git a/tests/ref/show-set-text-order-contained-1.png b/tests/ref/show-set-text-order-contained-1.png Binary files differnew file mode 100644 index 00000000..8deaaacd --- /dev/null +++ b/tests/ref/show-set-text-order-contained-1.png diff --git a/tests/ref/show-set-text-order-contained-2.png b/tests/ref/show-set-text-order-contained-2.png Binary files differnew file mode 100644 index 00000000..00ea3fb8 --- /dev/null +++ b/tests/ref/show-set-text-order-contained-2.png diff --git a/tests/ref/show-set-text-order-contained-3.png b/tests/ref/show-set-text-order-contained-3.png Binary files differnew file mode 100644 index 00000000..1bc95e3b --- /dev/null +++ b/tests/ref/show-set-text-order-contained-3.png diff --git a/tests/ref/show-set-text-order-contained-4.png b/tests/ref/show-set-text-order-contained-4.png Binary files differnew file mode 100644 index 00000000..0946f922 --- /dev/null +++ b/tests/ref/show-set-text-order-contained-4.png diff --git a/tests/ref/show-set-text-order-overlapping-1.png b/tests/ref/show-set-text-order-overlapping-1.png Binary files differnew file mode 100644 index 00000000..71222567 --- /dev/null +++ b/tests/ref/show-set-text-order-overlapping-1.png diff --git a/tests/ref/show-set-text-order-overlapping-2.png b/tests/ref/show-set-text-order-overlapping-2.png Binary files differnew file mode 100644 index 00000000..f1b658f2 --- /dev/null +++ b/tests/ref/show-set-text-order-overlapping-2.png diff --git a/tests/ref/show-set-vs-construct.png b/tests/ref/show-set-vs-construct.png Binary files differnew file mode 100644 index 00000000..a0ec96bf --- /dev/null +++ b/tests/ref/show-set-vs-construct.png diff --git a/tests/ref/show-set-where-override.png b/tests/ref/show-set-where-override.png Binary files differnew file mode 100644 index 00000000..7f1ec60d --- /dev/null +++ b/tests/ref/show-set-where-override.png diff --git a/tests/ref/show-text-basic.png b/tests/ref/show-text-basic.png Binary files differnew file mode 100644 index 00000000..29bb5840 --- /dev/null +++ b/tests/ref/show-text-basic.png diff --git a/tests/ref/show-text-cyclic-raw.png b/tests/ref/show-text-cyclic-raw.png Binary files differnew file mode 100644 index 00000000..b7521c44 --- /dev/null +++ b/tests/ref/show-text-cyclic-raw.png diff --git a/tests/ref/show-text-cyclic.png b/tests/ref/show-text-cyclic.png Binary files differnew file mode 100644 index 00000000..4c4c4886 --- /dev/null +++ b/tests/ref/show-text-cyclic.png diff --git a/tests/ref/show-text-exactly-once.png b/tests/ref/show-text-exactly-once.png Binary files differnew file mode 100644 index 00000000..f681f721 --- /dev/null +++ b/tests/ref/show-text-exactly-once.png diff --git a/tests/ref/show-text-get-text-on-it.png b/tests/ref/show-text-get-text-on-it.png Binary files differnew file mode 100644 index 00000000..5c75b9de --- /dev/null +++ b/tests/ref/show-text-get-text-on-it.png diff --git a/tests/ref/show-text-in-other-show.png b/tests/ref/show-text-in-other-show.png Binary files differnew file mode 100644 index 00000000..f29de999 --- /dev/null +++ b/tests/ref/show-text-in-other-show.png diff --git a/tests/ref/show-text-indirectly-cyclic.png b/tests/ref/show-text-indirectly-cyclic.png Binary files differnew file mode 100644 index 00000000..de166dca --- /dev/null +++ b/tests/ref/show-text-indirectly-cyclic.png diff --git a/tests/ref/show-text-path-resolving.png b/tests/ref/show-text-path-resolving.png Binary files differnew file mode 100644 index 00000000..1a04f9e6 --- /dev/null +++ b/tests/ref/show-text-path-resolving.png diff --git a/tests/ref/show-text-regex-case-insensitive.png b/tests/ref/show-text-regex-case-insensitive.png Binary files differnew file mode 100644 index 00000000..70d70d34 --- /dev/null +++ b/tests/ref/show-text-regex-case-insensitive.png diff --git a/tests/ref/show-text-regex-character-class.png b/tests/ref/show-text-regex-character-class.png Binary files differnew file mode 100644 index 00000000..946c5d22 --- /dev/null +++ b/tests/ref/show-text-regex-character-class.png diff --git a/tests/ref/show-text-regex-word-boundary.png b/tests/ref/show-text-regex-word-boundary.png Binary files differnew file mode 100644 index 00000000..c171ac02 --- /dev/null +++ b/tests/ref/show-text-regex-word-boundary.png diff --git a/tests/ref/show-text-regex.png b/tests/ref/show-text-regex.png Binary files differnew file mode 100644 index 00000000..85db10a3 --- /dev/null +++ b/tests/ref/show-text-regex.png diff --git a/tests/ref/show-where-folding-stroke.png b/tests/ref/show-where-folding-stroke.png Binary files differnew file mode 100644 index 00000000..186ce681 --- /dev/null +++ b/tests/ref/show-where-folding-stroke.png diff --git a/tests/ref/show-where-folding-text-size.png b/tests/ref/show-where-folding-text-size.png Binary files differnew file mode 100644 index 00000000..9fbe3ff9 --- /dev/null +++ b/tests/ref/show-where-folding-text-size.png diff --git a/tests/ref/show-where-optional-field-raw.png b/tests/ref/show-where-optional-field-raw.png Binary files differnew file mode 100644 index 00000000..dd381610 --- /dev/null +++ b/tests/ref/show-where-optional-field-raw.png diff --git a/tests/ref/show-where-optional-field-text.png b/tests/ref/show-where-optional-field-text.png Binary files differnew file mode 100644 index 00000000..b1367d09 --- /dev/null +++ b/tests/ref/show-where-optional-field-text.png diff --git a/tests/ref/show-where-resolving-hyphenate.png b/tests/ref/show-where-resolving-hyphenate.png Binary files differnew file mode 100644 index 00000000..052a2eda --- /dev/null +++ b/tests/ref/show-where-resolving-hyphenate.png diff --git a/tests/ref/show-where-resolving-length.png b/tests/ref/show-where-resolving-length.png Binary files differnew file mode 100644 index 00000000..4c77f2ac --- /dev/null +++ b/tests/ref/show-where-resolving-length.png diff --git a/tests/ref/smallcaps.png b/tests/ref/smallcaps.png Binary files differnew file mode 100644 index 00000000..b5ee12b7 --- /dev/null +++ b/tests/ref/smallcaps.png diff --git a/tests/ref/smartquote-apostrophe.png b/tests/ref/smartquote-apostrophe.png Binary files differnew file mode 100644 index 00000000..d2cc1ebf --- /dev/null +++ b/tests/ref/smartquote-apostrophe.png diff --git a/tests/ref/smartquote-custom-complex.png b/tests/ref/smartquote-custom-complex.png Binary files differnew file mode 100644 index 00000000..7204a997 --- /dev/null +++ b/tests/ref/smartquote-custom-complex.png diff --git a/tests/ref/smartquote-custom.png b/tests/ref/smartquote-custom.png Binary files differnew file mode 100644 index 00000000..6a6bd9d1 --- /dev/null +++ b/tests/ref/smartquote-custom.png diff --git a/tests/ref/smartquote-disable.png b/tests/ref/smartquote-disable.png Binary files differnew file mode 100644 index 00000000..0218b7ac --- /dev/null +++ b/tests/ref/smartquote-disable.png diff --git a/tests/ref/smartquote-disabled-temporarily.png b/tests/ref/smartquote-disabled-temporarily.png Binary files differnew file mode 100644 index 00000000..84bc5e32 --- /dev/null +++ b/tests/ref/smartquote-disabled-temporarily.png diff --git a/tests/ref/smartquote-empty.png b/tests/ref/smartquote-empty.png Binary files differnew file mode 100644 index 00000000..f9f19989 --- /dev/null +++ b/tests/ref/smartquote-empty.png diff --git a/tests/ref/smartquote-escape.png b/tests/ref/smartquote-escape.png Binary files differnew file mode 100644 index 00000000..45d8f602 --- /dev/null +++ b/tests/ref/smartquote-escape.png diff --git a/tests/ref/smartquote-nesting.png b/tests/ref/smartquote-nesting.png Binary files differnew file mode 100644 index 00000000..1f38c097 --- /dev/null +++ b/tests/ref/smartquote-nesting.png diff --git a/tests/ref/smartquote.png b/tests/ref/smartquote.png Binary files differnew file mode 100644 index 00000000..070e0487 --- /dev/null +++ b/tests/ref/smartquote.png diff --git a/tests/ref/space-collapsing-comments.png b/tests/ref/space-collapsing-comments.png Binary files differnew file mode 100644 index 00000000..b35d9fec --- /dev/null +++ b/tests/ref/space-collapsing-comments.png diff --git a/tests/ref/space-collapsing-linebreaks.png b/tests/ref/space-collapsing-linebreaks.png Binary files differnew file mode 100644 index 00000000..b1f4a3af --- /dev/null +++ b/tests/ref/space-collapsing-linebreaks.png diff --git a/tests/ref/space-collapsing-stringy-linebreak.png b/tests/ref/space-collapsing-stringy-linebreak.png Binary files differnew file mode 100644 index 00000000..ceec6da7 --- /dev/null +++ b/tests/ref/space-collapsing-stringy-linebreak.png diff --git a/tests/ref/space-collapsing-with-h.png b/tests/ref/space-collapsing-with-h.png Binary files differnew file mode 100644 index 00000000..c2e253e7 --- /dev/null +++ b/tests/ref/space-collapsing-with-h.png diff --git a/tests/ref/space-collapsing.png b/tests/ref/space-collapsing.png Binary files differnew file mode 100644 index 00000000..32bd6039 --- /dev/null +++ b/tests/ref/space-collapsing.png diff --git a/tests/ref/space-ideographic-kept.png b/tests/ref/space-ideographic-kept.png Binary files differnew file mode 100644 index 00000000..cd292e2d --- /dev/null +++ b/tests/ref/space-ideographic-kept.png diff --git a/tests/ref/space-thin-kept.png b/tests/ref/space-thin-kept.png Binary files differnew file mode 100644 index 00000000..6ed3504b --- /dev/null +++ b/tests/ref/space-thin-kept.png diff --git a/tests/ref/space-trailing-linebreak.png b/tests/ref/space-trailing-linebreak.png Binary files differnew file mode 100644 index 00000000..42b28264 --- /dev/null +++ b/tests/ref/space-trailing-linebreak.png diff --git a/tests/ref/spacing-h-and-v.png b/tests/ref/spacing-h-and-v.png Binary files differnew file mode 100644 index 00000000..2c9a2960 --- /dev/null +++ b/tests/ref/spacing-h-and-v.png diff --git a/tests/ref/spacing-rtl.png b/tests/ref/spacing-rtl.png Binary files differnew file mode 100644 index 00000000..a9cbbca6 --- /dev/null +++ b/tests/ref/spacing-rtl.png diff --git a/tests/ref/square-auto-sized.png b/tests/ref/square-auto-sized.png Binary files differnew file mode 100644 index 00000000..a2c4a36e --- /dev/null +++ b/tests/ref/square-auto-sized.png diff --git a/tests/ref/square-base.png b/tests/ref/square-base.png Binary files differnew file mode 100644 index 00000000..3ef753f2 --- /dev/null +++ b/tests/ref/square-base.png diff --git a/tests/ref/square-circle-alignment.png b/tests/ref/square-circle-alignment.png Binary files differnew file mode 100644 index 00000000..3fff9e66 --- /dev/null +++ b/tests/ref/square-circle-alignment.png diff --git a/tests/ref/square-circle-overspecified.png b/tests/ref/square-circle-overspecified.png Binary files differnew file mode 100644 index 00000000..6dde5e51 --- /dev/null +++ b/tests/ref/square-circle-overspecified.png diff --git a/tests/ref/square-contents-overflow.png b/tests/ref/square-contents-overflow.png Binary files differnew file mode 100644 index 00000000..ae65b0a8 --- /dev/null +++ b/tests/ref/square-contents-overflow.png diff --git a/tests/ref/square-height-limited-stack.png b/tests/ref/square-height-limited-stack.png Binary files differnew file mode 100644 index 00000000..f52c608d --- /dev/null +++ b/tests/ref/square-height-limited-stack.png diff --git a/tests/ref/square-height-limited.png b/tests/ref/square-height-limited.png Binary files differnew file mode 100644 index 00000000..c01dc426 --- /dev/null +++ b/tests/ref/square-height-limited.png diff --git a/tests/ref/square-overflow.png b/tests/ref/square-overflow.png Binary files differnew file mode 100644 index 00000000..6169f305 --- /dev/null +++ b/tests/ref/square-overflow.png diff --git a/tests/ref/square-rect-rounded.png b/tests/ref/square-rect-rounded.png Binary files differnew file mode 100644 index 00000000..678ba819 --- /dev/null +++ b/tests/ref/square-rect-rounded.png diff --git a/tests/ref/square-relative-size.png b/tests/ref/square-relative-size.png Binary files differnew file mode 100644 index 00000000..96e744e6 --- /dev/null +++ b/tests/ref/square-relative-size.png diff --git a/tests/ref/square-relatively-sized-child.png b/tests/ref/square-relatively-sized-child.png Binary files differnew file mode 100644 index 00000000..3ffe3105 --- /dev/null +++ b/tests/ref/square-relatively-sized-child.png diff --git a/tests/ref/square.png b/tests/ref/square.png Binary files differnew file mode 100644 index 00000000..e6f8f5c8 --- /dev/null +++ b/tests/ref/square.png diff --git a/tests/ref/stack-basic.png b/tests/ref/stack-basic.png Binary files differnew file mode 100644 index 00000000..b5f38a83 --- /dev/null +++ b/tests/ref/stack-basic.png diff --git a/tests/ref/stack-fr.png b/tests/ref/stack-fr.png Binary files differnew file mode 100644 index 00000000..e34dd9b1 --- /dev/null +++ b/tests/ref/stack-fr.png diff --git a/tests/ref/stack-overflow.png b/tests/ref/stack-overflow.png Binary files differnew file mode 100644 index 00000000..43b3625a --- /dev/null +++ b/tests/ref/stack-overflow.png diff --git a/tests/ref/stack-rtl-align-and-fr.png b/tests/ref/stack-rtl-align-and-fr.png Binary files differnew file mode 100644 index 00000000..653ade6f --- /dev/null +++ b/tests/ref/stack-rtl-align-and-fr.png diff --git a/tests/ref/stack-spacing.png b/tests/ref/stack-spacing.png Binary files differnew file mode 100644 index 00000000..9667f657 --- /dev/null +++ b/tests/ref/stack-spacing.png diff --git a/tests/ref/state-basic.png b/tests/ref/state-basic.png Binary files differnew file mode 100644 index 00000000..0c67a751 --- /dev/null +++ b/tests/ref/state-basic.png diff --git a/tests/ref/state-multiple-calls-same-key.png b/tests/ref/state-multiple-calls-same-key.png Binary files differnew file mode 100644 index 00000000..077b6792 --- /dev/null +++ b/tests/ref/state-multiple-calls-same-key.png diff --git a/tests/ref/state-nested.png b/tests/ref/state-nested.png Binary files differnew file mode 100644 index 00000000..cc701600 --- /dev/null +++ b/tests/ref/state-nested.png diff --git a/tests/ref/state-no-convergence.png b/tests/ref/state-no-convergence.png Binary files differnew file mode 100644 index 00000000..dd44b9e1 --- /dev/null +++ b/tests/ref/state-no-convergence.png diff --git a/tests/ref/strike-background.png b/tests/ref/strike-background.png Binary files differnew file mode 100644 index 00000000..01861d25 --- /dev/null +++ b/tests/ref/strike-background.png diff --git a/tests/ref/strike-with.png b/tests/ref/strike-with.png Binary files differnew file mode 100644 index 00000000..59a84150 --- /dev/null +++ b/tests/ref/strike-with.png diff --git a/tests/ref/stroke-composition.png b/tests/ref/stroke-composition.png Binary files differnew file mode 100644 index 00000000..a6c7ce70 --- /dev/null +++ b/tests/ref/stroke-composition.png diff --git a/tests/ref/stroke-folding.png b/tests/ref/stroke-folding.png Binary files differnew file mode 100644 index 00000000..b4f1b1a9 --- /dev/null +++ b/tests/ref/stroke-folding.png diff --git a/tests/ref/stroke-text.png b/tests/ref/stroke-text.png Binary files differnew file mode 100644 index 00000000..ac09053a --- /dev/null +++ b/tests/ref/stroke-text.png diff --git a/tests/ref/stroke-zero-thickness.png b/tests/ref/stroke-zero-thickness.png Binary files differnew file mode 100644 index 00000000..6d305eaf --- /dev/null +++ b/tests/ref/stroke-zero-thickness.png diff --git a/tests/ref/strong-delta.png b/tests/ref/strong-delta.png Binary files differnew file mode 100644 index 00000000..d32459f6 --- /dev/null +++ b/tests/ref/strong-delta.png diff --git a/tests/ref/strong-double-star-empty-hint.png b/tests/ref/strong-double-star-empty-hint.png Binary files differnew file mode 100644 index 00000000..29cbb90f --- /dev/null +++ b/tests/ref/strong-double-star-empty-hint.png diff --git a/tests/ref/sub-super-non-typographic.png b/tests/ref/sub-super-non-typographic.png Binary files differnew file mode 100644 index 00000000..e5a8b673 --- /dev/null +++ b/tests/ref/sub-super-non-typographic.png diff --git a/tests/ref/sub-super.png b/tests/ref/sub-super.png Binary files differnew file mode 100644 index 00000000..9359cf01 --- /dev/null +++ b/tests/ref/sub-super.png diff --git a/tests/ref/super-underline.png b/tests/ref/super-underline.png Binary files differnew file mode 100644 index 00000000..99c1c309 --- /dev/null +++ b/tests/ref/super-underline.png diff --git a/tests/ref/symbol-constructor.png b/tests/ref/symbol-constructor.png Binary files differnew file mode 100644 index 00000000..e6db9491 --- /dev/null +++ b/tests/ref/symbol-constructor.png diff --git a/tests/ref/symbol.png b/tests/ref/symbol.png Binary files differnew file mode 100644 index 00000000..37339d59 --- /dev/null +++ b/tests/ref/symbol.png diff --git a/tests/ref/table-align-array.png b/tests/ref/table-align-array.png Binary files differnew file mode 100644 index 00000000..9242ae12 --- /dev/null +++ b/tests/ref/table-align-array.png diff --git a/tests/ref/table-cell-align-override.png b/tests/ref/table-cell-align-override.png Binary files differnew file mode 100644 index 00000000..dfab2bb0 --- /dev/null +++ b/tests/ref/table-cell-align-override.png diff --git a/tests/ref/table-cell-folding.png b/tests/ref/table-cell-folding.png Binary files differnew file mode 100644 index 00000000..94897a92 --- /dev/null +++ b/tests/ref/table-cell-folding.png diff --git a/tests/ref/table-cell-override.png b/tests/ref/table-cell-override.png Binary files differnew file mode 100644 index 00000000..d6f37d63 --- /dev/null +++ b/tests/ref/table-cell-override.png diff --git a/tests/ref/table-cell-set.png b/tests/ref/table-cell-set.png Binary files differnew file mode 100644 index 00000000..ef720ab3 --- /dev/null +++ b/tests/ref/table-cell-set.png diff --git a/tests/ref/table-cell-show-and-override.png b/tests/ref/table-cell-show-and-override.png Binary files differnew file mode 100644 index 00000000..df745802 --- /dev/null +++ b/tests/ref/table-cell-show-and-override.png diff --git a/tests/ref/table-cell-show-based-on-position.png b/tests/ref/table-cell-show-based-on-position.png Binary files differnew file mode 100644 index 00000000..db46e260 --- /dev/null +++ b/tests/ref/table-cell-show-based-on-position.png diff --git a/tests/ref/table-cell-show-emph.png b/tests/ref/table-cell-show-emph.png Binary files differnew file mode 100644 index 00000000..1afc833b --- /dev/null +++ b/tests/ref/table-cell-show-emph.png diff --git a/tests/ref/table-cell-show.png b/tests/ref/table-cell-show.png Binary files differnew file mode 100644 index 00000000..9ac6d269 --- /dev/null +++ b/tests/ref/table-cell-show.png diff --git a/tests/ref/table-cell-various-overrides.png b/tests/ref/table-cell-various-overrides.png Binary files differnew file mode 100644 index 00000000..c8540dfe --- /dev/null +++ b/tests/ref/table-cell-various-overrides.png diff --git a/tests/ref/table-fill-basic.png b/tests/ref/table-fill-basic.png Binary files differnew file mode 100644 index 00000000..bc12f8ae --- /dev/null +++ b/tests/ref/table-fill-basic.png diff --git a/tests/ref/table-gutters.png b/tests/ref/table-gutters.png Binary files differnew file mode 100644 index 00000000..697ddd48 --- /dev/null +++ b/tests/ref/table-gutters.png diff --git a/tests/ref/table-inset-fold.png b/tests/ref/table-inset-fold.png Binary files differnew file mode 100644 index 00000000..f2985c9e --- /dev/null +++ b/tests/ref/table-inset-fold.png diff --git a/tests/ref/table-inset.png b/tests/ref/table-inset.png Binary files differnew file mode 100644 index 00000000..a8a9adda --- /dev/null +++ b/tests/ref/table-inset.png diff --git a/tests/ref/table-newlines.png b/tests/ref/table-newlines.png Binary files differnew file mode 100644 index 00000000..a4da25f3 --- /dev/null +++ b/tests/ref/table-newlines.png diff --git a/tests/ref/table-stroke-vline-position-left-and-right.png b/tests/ref/table-stroke-vline-position-left-and-right.png Binary files differnew file mode 100644 index 00000000..53b48a10 --- /dev/null +++ b/tests/ref/table-stroke-vline-position-left-and-right.png diff --git a/tests/ref/terms-built-in-loop.png b/tests/ref/terms-built-in-loop.png Binary files differnew file mode 100644 index 00000000..dc103af9 --- /dev/null +++ b/tests/ref/terms-built-in-loop.png diff --git a/tests/ref/terms-constructor.png b/tests/ref/terms-constructor.png Binary files differnew file mode 100644 index 00000000..fe161505 --- /dev/null +++ b/tests/ref/terms-constructor.png diff --git a/tests/ref/terms-grid.png b/tests/ref/terms-grid.png Binary files differnew file mode 100644 index 00000000..6142becf --- /dev/null +++ b/tests/ref/terms-grid.png diff --git a/tests/ref/terms-multiline.png b/tests/ref/terms-multiline.png Binary files differnew file mode 100644 index 00000000..b5baea4a --- /dev/null +++ b/tests/ref/terms-multiline.png diff --git a/tests/ref/terms-rtl.png b/tests/ref/terms-rtl.png Binary files differnew file mode 100644 index 00000000..538571dd --- /dev/null +++ b/tests/ref/terms-rtl.png diff --git a/tests/ref/terms-style-change-interrupted.png b/tests/ref/terms-style-change-interrupted.png Binary files differnew file mode 100644 index 00000000..846e45e1 --- /dev/null +++ b/tests/ref/terms-style-change-interrupted.png diff --git a/tests/ref/terms-syntax-edge-cases.png b/tests/ref/terms-syntax-edge-cases.png Binary files differnew file mode 100644 index 00000000..e2a557c1 --- /dev/null +++ b/tests/ref/terms-syntax-edge-cases.png diff --git a/tests/ref/text-alternates-and-stylistic-sets.png b/tests/ref/text-alternates-and-stylistic-sets.png Binary files differnew file mode 100644 index 00000000..877542fc --- /dev/null +++ b/tests/ref/text-alternates-and-stylistic-sets.png diff --git a/tests/ref/text-call-body.png b/tests/ref/text-call-body.png Binary files differnew file mode 100644 index 00000000..24cdeb9f --- /dev/null +++ b/tests/ref/text-call-body.png diff --git a/tests/ref/text-chinese-basic.png b/tests/ref/text-chinese-basic.png Binary files differnew file mode 100644 index 00000000..ea4a0b82 --- /dev/null +++ b/tests/ref/text-chinese-basic.png diff --git a/tests/ref/text-cjk-latin-spacing.png b/tests/ref/text-cjk-latin-spacing.png Binary files differnew file mode 100644 index 00000000..1906bf76 --- /dev/null +++ b/tests/ref/text-cjk-latin-spacing.png diff --git a/tests/ref/text-copy-paste-ligatures.png b/tests/ref/text-copy-paste-ligatures.png Binary files differnew file mode 100644 index 00000000..f0f36a86 --- /dev/null +++ b/tests/ref/text-copy-paste-ligatures.png diff --git a/tests/ref/text-edge.png b/tests/ref/text-edge.png Binary files differnew file mode 100644 index 00000000..0953eded --- /dev/null +++ b/tests/ref/text-edge.png diff --git a/tests/ref/text-features.png b/tests/ref/text-features.png Binary files differnew file mode 100644 index 00000000..7b0b391f --- /dev/null +++ b/tests/ref/text-features.png diff --git a/tests/ref/text-font-change-after-space.png b/tests/ref/text-font-change-after-space.png Binary files differnew file mode 100644 index 00000000..83d2ceb6 --- /dev/null +++ b/tests/ref/text-font-change-after-space.png diff --git a/tests/ref/text-font-just-a-space.png b/tests/ref/text-font-just-a-space.png Binary files differnew file mode 100644 index 00000000..3c91db3c --- /dev/null +++ b/tests/ref/text-font-just-a-space.png diff --git a/tests/ref/text-font-properties.png b/tests/ref/text-font-properties.png Binary files differnew file mode 100644 index 00000000..3c65fa33 --- /dev/null +++ b/tests/ref/text-font-properties.png diff --git a/tests/ref/text-kerning.png b/tests/ref/text-kerning.png Binary files differnew file mode 100644 index 00000000..1bd3a001 --- /dev/null +++ b/tests/ref/text-kerning.png diff --git a/tests/ref/text-lang-hyphenate.png b/tests/ref/text-lang-hyphenate.png Binary files differnew file mode 100644 index 00000000..6315d6e2 --- /dev/null +++ b/tests/ref/text-lang-hyphenate.png diff --git a/tests/ref/text-lang-region.png b/tests/ref/text-lang-region.png Binary files differnew file mode 100644 index 00000000..a2736578 --- /dev/null +++ b/tests/ref/text-lang-region.png diff --git a/tests/ref/text-lang-script-shaping.png b/tests/ref/text-lang-script-shaping.png Binary files differnew file mode 100644 index 00000000..6beaece4 --- /dev/null +++ b/tests/ref/text-lang-script-shaping.png diff --git a/tests/ref/text-lang-shaping.png b/tests/ref/text-lang-shaping.png Binary files differnew file mode 100644 index 00000000..b892fcd5 --- /dev/null +++ b/tests/ref/text-lang-shaping.png diff --git a/tests/ref/text-lang-unknown-region.png b/tests/ref/text-lang-unknown-region.png Binary files differnew file mode 100644 index 00000000..de63013e --- /dev/null +++ b/tests/ref/text-lang-unknown-region.png diff --git a/tests/ref/text-lang.png b/tests/ref/text-lang.png Binary files differnew file mode 100644 index 00000000..de63013e --- /dev/null +++ b/tests/ref/text-lang.png diff --git a/tests/ref/text-ligatures.png b/tests/ref/text-ligatures.png Binary files differnew file mode 100644 index 00000000..6f0e286c --- /dev/null +++ b/tests/ref/text-ligatures.png diff --git a/tests/ref/text-number-type.png b/tests/ref/text-number-type.png Binary files differnew file mode 100644 index 00000000..beb6ba6c --- /dev/null +++ b/tests/ref/text-number-type.png diff --git a/tests/ref/text-number-width.png b/tests/ref/text-number-width.png Binary files differnew file mode 100644 index 00000000..62d8c61b --- /dev/null +++ b/tests/ref/text-number-width.png diff --git a/tests/ref/text-size-em-nesting.png b/tests/ref/text-size-em-nesting.png Binary files differnew file mode 100644 index 00000000..34ae35fe --- /dev/null +++ b/tests/ref/text-size-em-nesting.png diff --git a/tests/ref/text-size-em.png b/tests/ref/text-size-em.png Binary files differnew file mode 100644 index 00000000..944bdd29 --- /dev/null +++ b/tests/ref/text-size-em.png diff --git a/tests/ref/text-slashed-zero-and-fractions.png b/tests/ref/text-slashed-zero-and-fractions.png Binary files differnew file mode 100644 index 00000000..a25ca023 --- /dev/null +++ b/tests/ref/text-slashed-zero-and-fractions.png diff --git a/tests/ref/text-spacing-relative.png b/tests/ref/text-spacing-relative.png Binary files differnew file mode 100644 index 00000000..ccd2f140 --- /dev/null +++ b/tests/ref/text-spacing-relative.png diff --git a/tests/ref/text-spacing.png b/tests/ref/text-spacing.png Binary files differnew file mode 100644 index 00000000..240c69c0 --- /dev/null +++ b/tests/ref/text-spacing.png diff --git a/tests/ref/text-tracking-arabic.png b/tests/ref/text-tracking-arabic.png Binary files differnew file mode 100644 index 00000000..a4e450ff --- /dev/null +++ b/tests/ref/text-tracking-arabic.png diff --git a/tests/ref/text-tracking-changed-temporarily.png b/tests/ref/text-tracking-changed-temporarily.png Binary files differnew file mode 100644 index 00000000..f27849b4 --- /dev/null +++ b/tests/ref/text-tracking-changed-temporarily.png diff --git a/tests/ref/text-tracking-mark-placement.png b/tests/ref/text-tracking-mark-placement.png Binary files differnew file mode 100644 index 00000000..7fc8bb19 --- /dev/null +++ b/tests/ref/text-tracking-mark-placement.png diff --git a/tests/ref/text-tracking-negative.png b/tests/ref/text-tracking-negative.png Binary files differnew file mode 100644 index 00000000..96589887 --- /dev/null +++ b/tests/ref/text-tracking-negative.png diff --git a/tests/ref/text/baseline.png b/tests/ref/text/baseline.png Binary files differdeleted file mode 100644 index dcd6eb12..00000000 --- a/tests/ref/text/baseline.png +++ /dev/null diff --git a/tests/ref/text/chinese.png b/tests/ref/text/chinese.png Binary files differdeleted file mode 100644 index 0c3ddd00..00000000 --- a/tests/ref/text/chinese.png +++ /dev/null diff --git a/tests/ref/text/copy-paste.png b/tests/ref/text/copy-paste.png Binary files differdeleted file mode 100644 index ae4a5ad9..00000000 --- a/tests/ref/text/copy-paste.png +++ /dev/null diff --git a/tests/ref/text/deco.png b/tests/ref/text/deco.png Binary files differdeleted file mode 100644 index 3a11e72f..00000000 --- a/tests/ref/text/deco.png +++ /dev/null diff --git a/tests/ref/text/edge.png b/tests/ref/text/edge.png Binary files differdeleted file mode 100644 index 1daf4c2f..00000000 --- a/tests/ref/text/edge.png +++ /dev/null diff --git a/tests/ref/text/em.png b/tests/ref/text/em.png Binary files differdeleted file mode 100644 index 04cccd53..00000000 --- a/tests/ref/text/em.png +++ /dev/null diff --git a/tests/ref/text/emoji.png b/tests/ref/text/emoji.png Binary files differdeleted file mode 100644 index 1dbbba79..00000000 --- a/tests/ref/text/emoji.png +++ /dev/null diff --git a/tests/ref/text/emphasis.png b/tests/ref/text/emphasis.png Binary files differdeleted file mode 100644 index c19f6ebb..00000000 --- a/tests/ref/text/emphasis.png +++ /dev/null diff --git a/tests/ref/text/escape.png b/tests/ref/text/escape.png Binary files differdeleted file mode 100644 index c94bc52f..00000000 --- a/tests/ref/text/escape.png +++ /dev/null diff --git a/tests/ref/text/fallback.png b/tests/ref/text/fallback.png Binary files differdeleted file mode 100644 index 7f1e3e38..00000000 --- a/tests/ref/text/fallback.png +++ /dev/null diff --git a/tests/ref/text/features.png b/tests/ref/text/features.png Binary files differdeleted file mode 100644 index 566694c6..00000000 --- a/tests/ref/text/features.png +++ /dev/null diff --git a/tests/ref/text/font.png b/tests/ref/text/font.png Binary files differdeleted file mode 100644 index 39c8a951..00000000 --- a/tests/ref/text/font.png +++ /dev/null diff --git a/tests/ref/text/hyphenate.png b/tests/ref/text/hyphenate.png Binary files differdeleted file mode 100644 index 7b386a51..00000000 --- a/tests/ref/text/hyphenate.png +++ /dev/null diff --git a/tests/ref/text/lang-with-region.png b/tests/ref/text/lang-with-region.png Binary files differdeleted file mode 100644 index c7753104..00000000 --- a/tests/ref/text/lang-with-region.png +++ /dev/null diff --git a/tests/ref/text/lang.png b/tests/ref/text/lang.png Binary files differdeleted file mode 100644 index a5ae8979..00000000 --- a/tests/ref/text/lang.png +++ /dev/null diff --git a/tests/ref/text/linebreak-link.png b/tests/ref/text/linebreak-link.png Binary files differdeleted file mode 100644 index ffe39caa..00000000 --- a/tests/ref/text/linebreak-link.png +++ /dev/null diff --git a/tests/ref/text/linebreak-obj.png b/tests/ref/text/linebreak-obj.png Binary files differdeleted file mode 100644 index 127ee687..00000000 --- a/tests/ref/text/linebreak-obj.png +++ /dev/null diff --git a/tests/ref/text/linebreak.png b/tests/ref/text/linebreak.png Binary files differdeleted file mode 100644 index 3dd2fc15..00000000 --- a/tests/ref/text/linebreak.png +++ /dev/null diff --git a/tests/ref/text/lorem.png b/tests/ref/text/lorem.png Binary files differdeleted file mode 100644 index 9d55df22..00000000 --- a/tests/ref/text/lorem.png +++ /dev/null diff --git a/tests/ref/text/microtype.png b/tests/ref/text/microtype.png Binary files differdeleted file mode 100644 index 87622b0f..00000000 --- a/tests/ref/text/microtype.png +++ /dev/null diff --git a/tests/ref/text/numbers.png b/tests/ref/text/numbers.png Binary files differdeleted file mode 100644 index 9fc76aae..00000000 --- a/tests/ref/text/numbers.png +++ /dev/null diff --git a/tests/ref/text/quote-nesting.png b/tests/ref/text/quote-nesting.png Binary files differdeleted file mode 100644 index fb16002d..00000000 --- a/tests/ref/text/quote-nesting.png +++ /dev/null diff --git a/tests/ref/text/quote.png b/tests/ref/text/quote.png Binary files differdeleted file mode 100644 index 653f2d17..00000000 --- a/tests/ref/text/quote.png +++ /dev/null diff --git a/tests/ref/text/quotes.png b/tests/ref/text/quotes.png Binary files differdeleted file mode 100644 index 535c2829..00000000 --- a/tests/ref/text/quotes.png +++ /dev/null diff --git a/tests/ref/text/raw-align.png b/tests/ref/text/raw-align.png Binary files differdeleted file mode 100644 index 6d1044f7..00000000 --- a/tests/ref/text/raw-align.png +++ /dev/null diff --git a/tests/ref/text/raw-code.png b/tests/ref/text/raw-code.png Binary files differdeleted file mode 100644 index 682c7c48..00000000 --- a/tests/ref/text/raw-code.png +++ /dev/null diff --git a/tests/ref/text/raw-line.png b/tests/ref/text/raw-line.png Binary files differdeleted file mode 100644 index b76eb808..00000000 --- a/tests/ref/text/raw-line.png +++ /dev/null diff --git a/tests/ref/text/raw-syntaxes.png b/tests/ref/text/raw-syntaxes.png Binary files differdeleted file mode 100644 index ada751e0..00000000 --- a/tests/ref/text/raw-syntaxes.png +++ /dev/null diff --git a/tests/ref/text/raw-tabs.png b/tests/ref/text/raw-tabs.png Binary files differdeleted file mode 100644 index cac265e9..00000000 --- a/tests/ref/text/raw-tabs.png +++ /dev/null diff --git a/tests/ref/text/raw-theme.png b/tests/ref/text/raw-theme.png Binary files differdeleted file mode 100644 index 0ce17760..00000000 --- a/tests/ref/text/raw-theme.png +++ /dev/null diff --git a/tests/ref/text/raw.png b/tests/ref/text/raw.png Binary files differdeleted file mode 100644 index 27120d74..00000000 --- a/tests/ref/text/raw.png +++ /dev/null diff --git a/tests/ref/text/shaping.png b/tests/ref/text/shaping.png Binary files differdeleted file mode 100644 index 69cba132..00000000 --- a/tests/ref/text/shaping.png +++ /dev/null diff --git a/tests/ref/text/shift.png b/tests/ref/text/shift.png Binary files differdeleted file mode 100644 index 09d68bac..00000000 --- a/tests/ref/text/shift.png +++ /dev/null diff --git a/tests/ref/text/smartquotes.png b/tests/ref/text/smartquotes.png Binary files differdeleted file mode 100644 index a6a8cbb5..00000000 --- a/tests/ref/text/smartquotes.png +++ /dev/null diff --git a/tests/ref/text/space.png b/tests/ref/text/space.png Binary files differdeleted file mode 100644 index bae0e0a8..00000000 --- a/tests/ref/text/space.png +++ /dev/null diff --git a/tests/ref/text/stroke.png b/tests/ref/text/stroke.png Binary files differdeleted file mode 100644 index d6d85c28..00000000 --- a/tests/ref/text/stroke.png +++ /dev/null diff --git a/tests/ref/text/symbol.png b/tests/ref/text/symbol.png Binary files differdeleted file mode 100644 index 04d9d77f..00000000 --- a/tests/ref/text/symbol.png +++ /dev/null diff --git a/tests/ref/text/tracking-spacing.png b/tests/ref/text/tracking-spacing.png Binary files differdeleted file mode 100644 index 68d80213..00000000 --- a/tests/ref/text/tracking-spacing.png +++ /dev/null diff --git a/tests/ref/transform-rotate-and-scale.png b/tests/ref/transform-rotate-and-scale.png Binary files differnew file mode 100644 index 00000000..0dcf67ed --- /dev/null +++ b/tests/ref/transform-rotate-and-scale.png diff --git a/tests/ref/transform-rotate-origin.png b/tests/ref/transform-rotate-origin.png Binary files differnew file mode 100644 index 00000000..152b1e1f --- /dev/null +++ b/tests/ref/transform-rotate-origin.png diff --git a/tests/ref/transform-rotate-relative-sizing.png b/tests/ref/transform-rotate-relative-sizing.png Binary files differnew file mode 100644 index 00000000..9b81c386 --- /dev/null +++ b/tests/ref/transform-rotate-relative-sizing.png diff --git a/tests/ref/transform-rotate.png b/tests/ref/transform-rotate.png Binary files differnew file mode 100644 index 00000000..3990ed5b --- /dev/null +++ b/tests/ref/transform-rotate.png diff --git a/tests/ref/transform-scale-origin.png b/tests/ref/transform-scale-origin.png Binary files differnew file mode 100644 index 00000000..10e1cfe2 --- /dev/null +++ b/tests/ref/transform-scale-origin.png diff --git a/tests/ref/transform-scale-relative-sizing.png b/tests/ref/transform-scale-relative-sizing.png Binary files differnew file mode 100644 index 00000000..d10bd3ff --- /dev/null +++ b/tests/ref/transform-scale-relative-sizing.png diff --git a/tests/ref/transform-scale.png b/tests/ref/transform-scale.png Binary files differnew file mode 100644 index 00000000..c95b90f1 --- /dev/null +++ b/tests/ref/transform-scale.png diff --git a/tests/ref/transform-tex-logo.png b/tests/ref/transform-tex-logo.png Binary files differnew file mode 100644 index 00000000..5d16ffb4 --- /dev/null +++ b/tests/ref/transform-tex-logo.png diff --git a/tests/ref/underline-background.png b/tests/ref/underline-background.png Binary files differnew file mode 100644 index 00000000..33ba381a --- /dev/null +++ b/tests/ref/underline-background.png diff --git a/tests/ref/underline-overline-strike.png b/tests/ref/underline-overline-strike.png Binary files differnew file mode 100644 index 00000000..2567fca4 --- /dev/null +++ b/tests/ref/underline-overline-strike.png diff --git a/tests/ref/underline-stroke-folding.png b/tests/ref/underline-stroke-folding.png Binary files differnew file mode 100644 index 00000000..32119e5c --- /dev/null +++ b/tests/ref/underline-stroke-folding.png diff --git a/tests/ref/visualize/gradient-conic.png b/tests/ref/visualize/gradient-conic.png Binary files differdeleted file mode 100644 index ff4a0ca2..00000000 --- a/tests/ref/visualize/gradient-conic.png +++ /dev/null diff --git a/tests/ref/visualize/gradient-dir.png b/tests/ref/visualize/gradient-dir.png Binary files differdeleted file mode 100644 index bda3eb17..00000000 --- a/tests/ref/visualize/gradient-dir.png +++ /dev/null diff --git a/tests/ref/visualize/gradient-hue-rotation.png b/tests/ref/visualize/gradient-hue-rotation.png Binary files differdeleted file mode 100644 index 2d786f71..00000000 --- a/tests/ref/visualize/gradient-hue-rotation.png +++ /dev/null diff --git a/tests/ref/visualize/gradient-math.png b/tests/ref/visualize/gradient-math.png Binary files differdeleted file mode 100644 index 470e6138..00000000 --- a/tests/ref/visualize/gradient-math.png +++ /dev/null diff --git a/tests/ref/visualize/gradient-presets.png b/tests/ref/visualize/gradient-presets.png Binary files differdeleted file mode 100644 index e6f7f73a..00000000 --- a/tests/ref/visualize/gradient-presets.png +++ /dev/null diff --git a/tests/ref/visualize/gradient-radial.png b/tests/ref/visualize/gradient-radial.png Binary files differdeleted file mode 100644 index 2e8e9af3..00000000 --- a/tests/ref/visualize/gradient-radial.png +++ /dev/null diff --git a/tests/ref/visualize/gradient-relative-conic.png b/tests/ref/visualize/gradient-relative-conic.png Binary files differdeleted file mode 100644 index 232c5f0a..00000000 --- a/tests/ref/visualize/gradient-relative-conic.png +++ /dev/null diff --git a/tests/ref/visualize/gradient-relative-linear.png b/tests/ref/visualize/gradient-relative-linear.png Binary files differdeleted file mode 100644 index 56e46119..00000000 --- a/tests/ref/visualize/gradient-relative-linear.png +++ /dev/null diff --git a/tests/ref/visualize/gradient-relative-radial.png b/tests/ref/visualize/gradient-relative-radial.png Binary files differdeleted file mode 100644 index 210ea7b0..00000000 --- a/tests/ref/visualize/gradient-relative-radial.png +++ /dev/null diff --git a/tests/ref/visualize/gradient-repeat.png b/tests/ref/visualize/gradient-repeat.png Binary files differdeleted file mode 100644 index 6be7dc66..00000000 --- a/tests/ref/visualize/gradient-repeat.png +++ /dev/null diff --git a/tests/ref/visualize/gradient-sharp.png b/tests/ref/visualize/gradient-sharp.png Binary files differdeleted file mode 100644 index b7698cfa..00000000 --- a/tests/ref/visualize/gradient-sharp.png +++ /dev/null diff --git a/tests/ref/visualize/gradient-stroke.png b/tests/ref/visualize/gradient-stroke.png Binary files differdeleted file mode 100644 index 69317f73..00000000 --- a/tests/ref/visualize/gradient-stroke.png +++ /dev/null diff --git a/tests/ref/visualize/gradient-text-decorations.png b/tests/ref/visualize/gradient-text-decorations.png Binary files differdeleted file mode 100644 index 887cd500..00000000 --- a/tests/ref/visualize/gradient-text-decorations.png +++ /dev/null diff --git a/tests/ref/visualize/gradient-text-other.png b/tests/ref/visualize/gradient-text-other.png Binary files differdeleted file mode 100644 index 78555b18..00000000 --- a/tests/ref/visualize/gradient-text-other.png +++ /dev/null diff --git a/tests/ref/visualize/gradient-text.png b/tests/ref/visualize/gradient-text.png Binary files differdeleted file mode 100644 index 478a0586..00000000 --- a/tests/ref/visualize/gradient-text.png +++ /dev/null diff --git a/tests/ref/visualize/gradient-transform.png b/tests/ref/visualize/gradient-transform.png Binary files differdeleted file mode 100644 index a55ad91e..00000000 --- a/tests/ref/visualize/gradient-transform.png +++ /dev/null diff --git a/tests/ref/visualize/image-scale.png b/tests/ref/visualize/image-scale.png Binary files differdeleted file mode 100644 index 95e9157e..00000000 --- a/tests/ref/visualize/image-scale.png +++ /dev/null diff --git a/tests/ref/visualize/image.png b/tests/ref/visualize/image.png Binary files differdeleted file mode 100644 index ec53fa98..00000000 --- a/tests/ref/visualize/image.png +++ /dev/null diff --git a/tests/ref/visualize/line.png b/tests/ref/visualize/line.png Binary files differdeleted file mode 100644 index d19dea0e..00000000 --- a/tests/ref/visualize/line.png +++ /dev/null diff --git a/tests/ref/visualize/path.png b/tests/ref/visualize/path.png Binary files differdeleted file mode 100644 index c7f710c9..00000000 --- a/tests/ref/visualize/path.png +++ /dev/null diff --git a/tests/ref/visualize/pattern-relative.png b/tests/ref/visualize/pattern-relative.png Binary files differdeleted file mode 100644 index 7958bf7f..00000000 --- a/tests/ref/visualize/pattern-relative.png +++ /dev/null diff --git a/tests/ref/visualize/pattern-simple.png b/tests/ref/visualize/pattern-simple.png Binary files differdeleted file mode 100644 index ac473a75..00000000 --- a/tests/ref/visualize/pattern-simple.png +++ /dev/null diff --git a/tests/ref/visualize/pattern-small.png b/tests/ref/visualize/pattern-small.png Binary files differdeleted file mode 100644 index 6af592dd..00000000 --- a/tests/ref/visualize/pattern-small.png +++ /dev/null diff --git a/tests/ref/visualize/pattern-spacing.png b/tests/ref/visualize/pattern-spacing.png Binary files differdeleted file mode 100644 index 4c95a3b0..00000000 --- a/tests/ref/visualize/pattern-spacing.png +++ /dev/null diff --git a/tests/ref/visualize/pattern-stroke.png b/tests/ref/visualize/pattern-stroke.png Binary files differdeleted file mode 100644 index d71f1c92..00000000 --- a/tests/ref/visualize/pattern-stroke.png +++ /dev/null diff --git a/tests/ref/visualize/pattern-text.png b/tests/ref/visualize/pattern-text.png Binary files differdeleted file mode 100644 index 2ecf2fda..00000000 --- a/tests/ref/visualize/pattern-text.png +++ /dev/null diff --git a/tests/ref/visualize/polygon.png b/tests/ref/visualize/polygon.png Binary files differdeleted file mode 100644 index 234aeb14..00000000 --- a/tests/ref/visualize/polygon.png +++ /dev/null diff --git a/tests/ref/visualize/shape-aspect.png b/tests/ref/visualize/shape-aspect.png Binary files differdeleted file mode 100644 index 918a5e73..00000000 --- a/tests/ref/visualize/shape-aspect.png +++ /dev/null diff --git a/tests/ref/visualize/shape-circle.png b/tests/ref/visualize/shape-circle.png Binary files differdeleted file mode 100644 index a2ee279d..00000000 --- a/tests/ref/visualize/shape-circle.png +++ /dev/null diff --git a/tests/ref/visualize/shape-ellipse.png b/tests/ref/visualize/shape-ellipse.png Binary files differdeleted file mode 100644 index 6de5e9f6..00000000 --- a/tests/ref/visualize/shape-ellipse.png +++ /dev/null diff --git a/tests/ref/visualize/shape-fill-stroke.png b/tests/ref/visualize/shape-fill-stroke.png Binary files differdeleted file mode 100644 index d4a4817a..00000000 --- a/tests/ref/visualize/shape-fill-stroke.png +++ /dev/null diff --git a/tests/ref/visualize/shape-rect.png b/tests/ref/visualize/shape-rect.png Binary files differdeleted file mode 100644 index a279341e..00000000 --- a/tests/ref/visualize/shape-rect.png +++ /dev/null diff --git a/tests/ref/visualize/shape-rounded.png b/tests/ref/visualize/shape-rounded.png Binary files differdeleted file mode 100644 index ec926d0a..00000000 --- a/tests/ref/visualize/shape-rounded.png +++ /dev/null diff --git a/tests/ref/visualize/shape-square.png b/tests/ref/visualize/shape-square.png Binary files differdeleted file mode 100644 index 46e243e1..00000000 --- a/tests/ref/visualize/shape-square.png +++ /dev/null diff --git a/tests/ref/visualize/stroke.png b/tests/ref/visualize/stroke.png Binary files differdeleted file mode 100644 index bdfcae9f..00000000 --- a/tests/ref/visualize/stroke.png +++ /dev/null diff --git a/tests/ref/visualize/svg-text.png b/tests/ref/visualize/svg-text.png Binary files differdeleted file mode 100644 index b2bbe320..00000000 --- a/tests/ref/visualize/svg-text.png +++ /dev/null diff --git a/tests/ref/while-loop-basic.png b/tests/ref/while-loop-basic.png Binary files differnew file mode 100644 index 00000000..3a0e6d24 --- /dev/null +++ b/tests/ref/while-loop-basic.png diff --git a/tests/src/args.rs b/tests/src/args.rs new file mode 100644 index 00000000..fcd4ead1 --- /dev/null +++ b/tests/src/args.rs @@ -0,0 +1,46 @@ +use clap::{Parser, Subcommand}; + +/// Typst's test runner. +#[derive(Debug, Clone, Parser)] +#[clap(name = "typst-test", author)] +pub struct CliArguments { + /// The command to run. + #[command(subcommand)] + pub command: Option<Command>, + /// All the tests that contain the filter string will be run. + pub filter: Vec<String>, + /// Runs only the tests with the exact specified `filter` names. + #[arg(short, long)] + pub exact: bool, + /// Whether to update the reference images of non-passing tests. + #[arg(short, long)] + pub update: bool, + /// The scaling factor to render the output image with. + /// + /// Does not affect the comparison or the reference image. + #[arg(short, long, default_value_t = 1.0)] + pub scale: f32, + /// Exports PDF outputs into the artifact store. + #[arg(long)] + pub pdf: bool, + /// Exports SVG outputs into the artifact store. + #[arg(long)] + pub svg: bool, + /// Whether to display the syntax tree. + #[arg(long)] + pub syntax: bool, + /// Prevents the terminal from being cleared of test names. + #[arg(short, long)] + pub verbose: bool, + /// How many threads to spawn when running the tests. + #[arg(short = 'j', long)] + pub num_threads: Option<usize>, +} + +/// What to do. +#[derive(Debug, Clone, Subcommand)] +#[command()] +pub enum Command { + /// Clears the on-disk test artifact store. + Clean, +} diff --git a/tests/src/collect.rs b/tests/src/collect.rs new file mode 100644 index 00000000..44a325f2 --- /dev/null +++ b/tests/src/collect.rs @@ -0,0 +1,420 @@ +use std::collections::{HashMap, HashSet}; +use std::fmt::{self, Display, Formatter}; +use std::ops::Range; +use std::path::{Path, PathBuf}; +use std::str::FromStr; + +use ecow::{eco_format, EcoString}; +use typst::syntax::package::PackageVersion; +use typst::syntax::{is_id_continue, is_ident, is_newline, FileId, Source, VirtualPath}; +use unscanny::Scanner; + +/// Collects all tests from all files. +/// +/// Returns: +/// - the tests and the number of skipped tests in the success case. +/// - parsing errors in the failure case. +pub fn collect() -> Result<(Vec<Test>, usize), Vec<TestParseError>> { + Collector::new().collect() +} + +/// A single test. +pub struct Test { + pub pos: FilePos, + pub name: EcoString, + pub source: Source, + pub notes: Vec<Note>, + pub large: bool, +} + +impl Display for Test { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{} ({})", self.name, self.pos) + } +} + +/// A position in a file. +#[derive(Clone)] +pub struct FilePos { + pub path: PathBuf, + pub line: usize, +} + +impl FilePos { + fn new(path: impl Into<PathBuf>, line: usize) -> Self { + Self { path: path.into(), line } + } +} + +impl Display for FilePos { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}:{}", self.path.display(), self.line) + } +} + +/// The size of a file. +pub struct FileSize(pub usize); + +impl Display for FileSize { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{:.2} KiB", (self.0 as f64) / 1024.0) + } +} + +/// An annotation like `// Error: 2-6 message` in a test. +pub struct Note { + pub pos: FilePos, + pub kind: NoteKind, + pub range: Option<Range<usize>>, + pub message: String, +} + +/// A kind of annotation in a test. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum NoteKind { + Error, + Warning, + Hint, +} + +impl FromStr for NoteKind { + type Err = (); + + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(match s { + "Error" => Self::Error, + "Warning" => Self::Warning, + "Hint" => Self::Hint, + _ => return Err(()), + }) + } +} + +impl Display for NoteKind { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.pad(match self { + Self::Error => "Error", + Self::Warning => "Warning", + Self::Hint => "Hint", + }) + } +} + +/// Collects all tests from all files. +struct Collector { + tests: Vec<Test>, + errors: Vec<TestParseError>, + seen: HashMap<EcoString, FilePos>, + large: HashSet<EcoString>, + skipped: usize, +} + +impl Collector { + /// Creates a new test collector. + fn new() -> Self { + Self { + tests: vec![], + errors: vec![], + seen: HashMap::new(), + large: HashSet::new(), + skipped: 0, + } + } + + /// Collects tests from all files. + fn collect(mut self) -> Result<(Vec<Test>, usize), Vec<TestParseError>> { + self.walk_files(); + self.walk_references(); + + if self.errors.is_empty() { + Ok((self.tests, self.skipped)) + } else { + Err(self.errors) + } + } + + /// Walks through all test files and collects the tests. + fn walk_files(&mut self) { + for entry in walkdir::WalkDir::new(crate::SUITE_PATH).sort_by_file_name() { + let entry = entry.unwrap(); + let path = entry.path(); + if !path.extension().is_some_and(|ext| ext == "typ") { + continue; + } + + let text = std::fs::read_to_string(path).unwrap(); + if text.starts_with("// SKIP") { + continue; + } + + Parser::new(self, path, &text).parse(); + } + } + + /// Walks through all reference images and ensure that a test exists for + /// each one. + fn walk_references(&mut self) { + for entry in walkdir::WalkDir::new(crate::REF_PATH).sort_by_file_name() { + let entry = entry.unwrap(); + let path = entry.path(); + if !path.extension().is_some_and(|ext| ext == "png") { + continue; + } + + let stem = path.file_stem().unwrap().to_string_lossy(); + let name = &*stem; + + let Some(pos) = self.seen.get(name) else { + self.errors.push(TestParseError { + pos: FilePos::new(path, 0), + message: "dangling reference image".into(), + }); + continue; + }; + + let len = path.metadata().unwrap().len() as usize; + if !self.large.contains(name) && len > crate::REF_LIMIT { + self.errors.push(TestParseError { + pos: pos.clone(), + message: format!( + "reference image size exceeds {}, but the test is not marked as `// LARGE`", + FileSize(crate::REF_LIMIT), + ), + }); + } + } + } +} + +/// Parses a single test file. +struct Parser<'a> { + collector: &'a mut Collector, + path: &'a Path, + s: Scanner<'a>, + test_start_line: usize, + line: usize, +} + +impl<'a> Parser<'a> { + /// Creates a new parser for a file. + fn new(collector: &'a mut Collector, path: &'a Path, source: &'a str) -> Self { + Self { + collector, + path, + s: Scanner::new(source), + test_start_line: 1, + line: 1, + } + } + + /// Parses an individual file. + fn parse(&mut self) { + self.skip_preamble(); + + while !self.s.done() { + let mut name = EcoString::new(); + let mut notes = vec![]; + if self.s.eat_if("---") { + self.s.eat_while(' '); + name = self.s.eat_until(char::is_whitespace).into(); + self.s.eat_while(' '); + + if name.is_empty() { + self.error("expected test name"); + } else if !is_ident(&name) { + self.error(format!("test name `{name}` is not a valid identifier")); + } else if !self.s.eat_if("---") { + self.error("expected closing ---"); + } + } else { + self.error("expected opening ---"); + } + + if self.collector.seen.contains_key(&name) { + self.error(format!("duplicate test {name}")); + } + + if self.s.eat_newline() { + self.line += 1; + } + + let start = self.s.cursor(); + self.test_start_line = self.line; + + let pos = FilePos::new(self.path, self.test_start_line); + self.collector.seen.insert(name.clone(), pos.clone()); + + while !self.s.done() && !self.s.at("---") { + self.s.eat_until(is_newline); + if self.s.eat_newline() { + self.line += 1; + } + } + + let text = self.s.from(start); + let large = text.starts_with("// LARGE"); + if large { + self.collector.large.insert(name.clone()); + } + + if !filtered(&name) { + self.collector.skipped += 1; + continue; + } + + let vpath = VirtualPath::new(self.path); + let source = Source::new(FileId::new(None, vpath), text.into()); + + self.s.jump(start); + self.line = self.test_start_line; + + while !self.s.done() && !self.s.at("---") { + self.s.eat_while(' '); + if self.s.eat_if("// ") { + notes.extend(self.parse_note(&source)); + } + + self.s.eat_until(is_newline); + if self.s.eat_newline() { + self.line += 1; + } + } + + self.collector.tests.push(Test { pos, name, source, notes, large }); + } + } + + /// Skips the preamble of a test. + fn skip_preamble(&mut self) { + let mut errored = false; + while !self.s.done() && !self.s.at("---") { + let line = self.s.eat_until(is_newline).trim(); + if !errored && !line.is_empty() && !line.starts_with("//") { + self.error("test preamble may only contain comments and blank lines"); + errored = true; + } + if self.s.eat_newline() { + self.line += 1; + } + } + } + + /// Parses an annotation in a test. + fn parse_note(&mut self, source: &Source) -> Option<Note> { + let head = self.s.eat_while(is_id_continue); + if !self.s.eat_if(':') { + return None; + } + + let kind: NoteKind = head.parse().ok()?; + self.s.eat_if(' '); + + let mut range = None; + if self.s.at('-') || self.s.at(char::is_numeric) { + range = self.parse_range(source); + if range.is_none() { + self.error("range is malformed"); + return None; + } + } + + let message = self + .s + .eat_until(is_newline) + .trim() + .replace("VERSION", &eco_format!("{}", PackageVersion::compiler())); + + Some(Note { + pos: FilePos::new(self.path, self.line), + kind, + range, + message, + }) + } + + /// Parse a range, optionally abbreviated as just a position if the range + /// is empty. + fn parse_range(&mut self, source: &Source) -> Option<Range<usize>> { + let start = self.parse_position(source)?; + let end = if self.s.eat_if('-') { self.parse_position(source)? } else { start }; + Some(start..end) + } + + /// Parses a relative `(line:)?column` position. + fn parse_position(&mut self, source: &Source) -> Option<usize> { + let first = self.parse_number()?; + let (line_delta, column) = + if self.s.eat_if(':') { (first, self.parse_number()?) } else { (1, first) }; + + let text = source.text(); + let line_idx_in_test = self.line - self.test_start_line; + let comments = text + .lines() + .skip(line_idx_in_test + 1) + .take_while(|line| line.trim().starts_with("//")) + .count(); + + let line_idx = (line_idx_in_test + comments).checked_add_signed(line_delta)?; + let column_idx = if column < 0 { + // Negative column index is from the back. + let range = source.line_to_range(line_idx)?; + text[range].chars().count().saturating_add_signed(column) + } else { + usize::try_from(column).ok()?.checked_sub(1)? + }; + + source.line_column_to_byte(line_idx, column_idx) + } + + /// Parse a number. + fn parse_number(&mut self) -> Option<isize> { + let start = self.s.cursor(); + self.s.eat_if('-'); + self.s.eat_while(char::is_numeric); + self.s.from(start).parse().ok() + } + + /// Stores a test parsing error. + fn error(&mut self, message: impl Into<String>) { + self.collector.errors.push(TestParseError { + pos: FilePos::new(self.path, self.line), + message: message.into(), + }); + } +} + +/// Whether a test is within the filtered set. +fn filtered(name: &str) -> bool { + let exact = crate::ARGS.exact; + let filter = &crate::ARGS.filter; + filter.is_empty() + || filter + .iter() + .any(|v| if exact { name == v } else { name.contains(v) }) +} + +/// An error in a test file. +pub struct TestParseError { + pos: FilePos, + message: String, +} + +impl Display for TestParseError { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{} ({})", self.message, self.pos) + } +} + +trait ScannerExt { + fn eat_newline(&mut self) -> bool; +} + +impl ScannerExt for Scanner<'_> { + fn eat_newline(&mut self) -> bool { + let ate = self.eat_if(is_newline); + if ate && self.before().ends_with('\r') { + self.eat_if('\n'); + } + ate + } +} diff --git a/tests/src/logger.rs b/tests/src/logger.rs new file mode 100644 index 00000000..c48650a7 --- /dev/null +++ b/tests/src/logger.rs @@ -0,0 +1,141 @@ +use std::io::{self, IsTerminal, StderrLock, Write}; +use std::time::{Duration, Instant}; + +use crate::collect::Test; +use crate::run::TestResult; + +/// Receives status updates by individual test runs. +pub struct Logger<'a> { + filtered: usize, + passed: usize, + failed: usize, + skipped: usize, + mismatched_image: bool, + active: Vec<&'a Test>, + last_change: Instant, + temp_lines: usize, + terminal: bool, +} + +impl<'a> Logger<'a> { + /// Create a new logger. + pub fn new(filtered: usize, skipped: usize) -> Self { + Self { + filtered, + passed: 0, + failed: 0, + skipped, + mismatched_image: false, + active: vec![], + temp_lines: 0, + last_change: Instant::now(), + terminal: std::io::stderr().is_terminal(), + } + } + + /// Register the start of a test. + pub fn start(&mut self, test: &'a Test) { + self.active.push(test); + self.last_change = Instant::now(); + self.refresh(); + } + + /// Register a finished test. + pub fn end(&mut self, test: &'a Test, result: std::thread::Result<TestResult>) { + self.active.retain(|t| t.name != test.name); + + let result = match result { + Ok(result) => result, + Err(_) => { + self.failed += 1; + self.temp_lines = 0; + self.print(move |out| { + writeln!(out, "❌ {test} panicked")?; + Ok(()) + }) + .unwrap(); + return; + } + }; + + if result.is_ok() { + self.passed += 1; + } else { + self.failed += 1; + } + + self.mismatched_image |= result.mismatched_image; + self.last_change = Instant::now(); + + self.print(move |out| { + if !result.errors.is_empty() { + writeln!(out, "❌ {test}")?; + for line in result.errors.lines() { + writeln!(out, " {line}")?; + } + } else if crate::ARGS.verbose || !result.infos.is_empty() { + writeln!(out, "✅ {test}")?; + } + for line in result.infos.lines() { + writeln!(out, " {line}")?; + } + Ok(()) + }) + .unwrap(); + } + + /// Prints a summary and returns whether the test suite passed. + pub fn finish(&self) -> bool { + let Self { filtered, passed, failed, skipped, .. } = *self; + + eprintln!("{passed} passed, {failed} failed, {skipped} skipped"); + assert_eq!(filtered, passed + failed, "not all tests were executed succesfully"); + + if self.mismatched_image { + eprintln!(" pass the --update flag to update the reference images"); + } + + self.failed == 0 + } + + /// Refresh the status. + pub fn refresh(&mut self) { + self.print(|_| Ok(())).unwrap(); + } + + /// Refresh the status print. + fn print( + &mut self, + inner: impl FnOnce(&mut StderrLock<'_>) -> io::Result<()>, + ) -> io::Result<()> { + let mut out = std::io::stderr().lock(); + + // Clear the status lines. + for _ in 0..self.temp_lines { + write!(out, "\x1B[1F\x1B[0J")?; + self.temp_lines = 0; + } + + // Print the result of a finished test. + inner(&mut out)?; + + // Print the status line. + let done = self.failed + self.passed; + if done < self.filtered { + if self.last_change.elapsed() > Duration::from_secs(2) { + for test in &self.active { + writeln!(out, "⏰ {test} is taking a long time ...")?; + if self.terminal { + self.temp_lines += 1; + } + } + } + if self.terminal { + writeln!(out, "💨 {done} / {}", self.filtered)?; + self.temp_lines += 1; + } + } + + Ok(()) + } +} diff --git a/tests/src/metadata.rs b/tests/src/metadata.rs deleted file mode 100644 index 53cbbdff..00000000 --- a/tests/src/metadata.rs +++ /dev/null @@ -1,334 +0,0 @@ -use std::collections::HashSet; -use std::fmt::{self, Display, Formatter}; -use std::ops::Range; -use std::str::FromStr; - -use ecow::EcoString; -use typst::syntax::package::PackageVersion; -use typst::syntax::Source; -use unscanny::Scanner; - -/// Each test and subset may contain metadata. -#[derive(Debug)] -pub struct TestMetadata { - /// Configures how the test is run. - pub config: TestConfig, - /// Declares properties that must hold for a test. - /// - /// For instance, `// Warning: 1-3 no text within underscores` - /// will fail the test if the warning isn't generated by your test. - pub annotations: HashSet<Annotation>, -} - -/// Configuration of a test or subtest. -#[derive(Debug, Default)] -pub struct TestConfig { - /// Reference images will be generated and compared. - /// - /// Defaults to `true`, can be disabled with `Ref: false`. - pub compare_ref: Option<bool>, - /// Hint annotations will be compared to compiler hints. - /// - /// Defaults to `true`, can be disabled with `Hints: false`. - pub validate_hints: Option<bool>, - /// Autocompletion annotations will be validated against autocompletions. - /// Mutually exclusive with error and hint annotations. - /// - /// Defaults to `false`, can be enabled with `Autocomplete: true`. - pub validate_autocomplete: Option<bool>, -} - -/// Parsing error when the metadata is invalid. -pub(crate) enum InvalidMetadata { - /// An invalid annotation and it's error message. - InvalidAnnotation(Annotation, String), - /// Setting metadata can only be done with `true` or `false` as a value. - InvalidSet(String), -} - -impl InvalidMetadata { - pub(crate) fn write( - invalid_data: Vec<InvalidMetadata>, - output: &mut String, - print_annotation: &mut impl FnMut(&Annotation, &mut String), - ) { - use std::fmt::Write; - for data in invalid_data.into_iter() { - let (annotation, error) = match data { - InvalidMetadata::InvalidAnnotation(a, e) => (Some(a), e), - InvalidMetadata::InvalidSet(e) => (None, e), - }; - write!(output, "{error}",).unwrap(); - if let Some(annotation) = annotation { - print_annotation(&annotation, output) - } else { - writeln!(output).unwrap(); - } - } - } -} - -/// Annotation of the form `// KIND: RANGE TEXT`. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct Annotation { - /// Which kind of annotation this is. - pub kind: AnnotationKind, - /// May be written as: - /// - `{line}:{col}-{line}:{col}`, e.g. `0:4-0:6`. - /// - `{col}-{col}`, e.g. `4-6`: - /// The line is assumed to be the line after the annotation. - /// - `-1`: Produces a range of length zero at the end of the next line. - /// Mostly useful for autocompletion tests which require an index. - pub range: Option<Range<usize>>, - /// The raw text after the annotation. - pub text: EcoString, -} - -/// The different kinds of in-test annotations. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum AnnotationKind { - Error, - Warning, - Hint, - AutocompleteContains, - AutocompleteExcludes, -} - -impl AnnotationKind { - /// Returns the user-facing string for this annotation. - pub fn as_str(self) -> &'static str { - match self { - AnnotationKind::Error => "Error", - AnnotationKind::Warning => "Warning", - AnnotationKind::Hint => "Hint", - AnnotationKind::AutocompleteContains => "Autocomplete contains", - AnnotationKind::AutocompleteExcludes => "Autocomplete excludes", - } - } -} - -impl FromStr for AnnotationKind { - type Err = &'static str; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - Ok(match s { - "Error" => AnnotationKind::Error, - "Warning" => AnnotationKind::Warning, - "Hint" => AnnotationKind::Hint, - "Autocomplete contains" => AnnotationKind::AutocompleteContains, - "Autocomplete excludes" => AnnotationKind::AutocompleteExcludes, - _ => return Err("invalid annotatino"), - }) - } -} - -impl Display for AnnotationKind { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.pad(self.as_str()) - } -} - -/// Parse metadata for a test. -pub fn parse_part_metadata( - source: &Source, - is_header: bool, -) -> Result<TestMetadata, Vec<InvalidMetadata>> { - let mut config = TestConfig::default(); - let mut annotations = HashSet::default(); - let mut invalid_data = vec![]; - - let lines = source_to_lines(source); - - for (i, line) in lines.iter().enumerate() { - if let Some((key, value)) = parse_metadata_line(line) { - let key = key.trim(); - match key { - "Ref" => validate_set_annotation( - value, - &mut config.compare_ref, - &mut invalid_data, - ), - "Hints" => validate_set_annotation( - value, - &mut config.validate_hints, - &mut invalid_data, - ), - "Autocomplete" => validate_set_annotation( - value, - &mut config.validate_autocomplete, - &mut invalid_data, - ), - annotation_key => { - let Ok(kind) = AnnotationKind::from_str(annotation_key) else { - continue; - }; - let mut s = Scanner::new(value); - let range = parse_range(&mut s, i, source); - let rest = if range.is_some() { s.after() } else { s.string() }; - let message = rest - .trim() - .replace("VERSION", &PackageVersion::compiler().to_string()) - .into(); - - let annotation = - Annotation { kind, range: range.clone(), text: message }; - - if is_header { - invalid_data.push(InvalidMetadata::InvalidAnnotation( - annotation, - format!( - "Error: header may not contain annotations of type {kind}" - ), - )); - continue; - } - - if matches!( - kind, - AnnotationKind::AutocompleteContains - | AnnotationKind::AutocompleteExcludes - ) { - if let Some(range) = range { - if range.start != range.end { - invalid_data.push(InvalidMetadata::InvalidAnnotation( - annotation, - "Error: found range in Autocomplete annotation where range.start != range.end, range.end would be ignored." - .to_string() - )); - continue; - } - } else { - invalid_data.push(InvalidMetadata::InvalidAnnotation( - annotation, - "Error: autocomplete annotation but no range specified" - .to_string(), - )); - continue; - } - } - annotations.insert(annotation); - } - } - } - } - if invalid_data.is_empty() { - Ok(TestMetadata { config, annotations }) - } else { - Err(invalid_data) - } -} - -/// Extract key and value for a metadata line of the form: `// KEY: VALUE`. -fn parse_metadata_line(line: &str) -> Option<(&str, &str)> { - let mut s = Scanner::new(line); - if !s.eat_if("// ") { - return None; - } - - let key = s.eat_until(':').trim(); - if !s.eat_if(':') { - return None; - } - - let value = s.eat_until('\n').trim(); - Some((key, value)) -} - -/// Parse a quoted string. -fn parse_string<'a>(s: &mut Scanner<'a>) -> Option<&'a str> { - if !s.eat_if('"') { - return None; - } - let sub = s.eat_until('"'); - if !s.eat_if('"') { - return None; - } - - Some(sub) -} - -/// Parse a number. -fn parse_num(s: &mut Scanner) -> Option<isize> { - let mut first = true; - let n = &s.eat_while(|c: char| { - let valid = first && c == '-' || c.is_numeric(); - first = false; - valid - }); - n.parse().ok() -} - -/// Parse a comma-separated list of strings. -pub fn parse_string_list(text: &str) -> HashSet<&str> { - let mut s = Scanner::new(text); - let mut result = HashSet::new(); - while let Some(sub) = parse_string(&mut s) { - result.insert(sub); - s.eat_whitespace(); - if !s.eat_if(',') { - break; - } - s.eat_whitespace(); - } - result -} - -/// Parse a position. -fn parse_pos(s: &mut Scanner, i: usize, source: &Source) -> Option<usize> { - let first = parse_num(s)? - 1; - let (delta, column) = - if s.eat_if(':') { (first, parse_num(s)? - 1) } else { (0, first) }; - let line = (i + comments_until_code(source, i)).checked_add_signed(delta)?; - source.line_column_to_byte(line, usize::try_from(column).ok()?) -} - -/// Parse a range. -fn parse_range(s: &mut Scanner, i: usize, source: &Source) -> Option<Range<usize>> { - let lines = source_to_lines(source); - s.eat_whitespace(); - if s.eat_if("-1") { - let mut add = 1; - while let Some(line) = lines.get(i + add) { - if !line.starts_with("//") { - break; - } - add += 1; - } - let next_line = lines.get(i + add)?; - let col = next_line.chars().count(); - - let index = source.line_column_to_byte(i + add, col)?; - s.eat_whitespace(); - return Some(index..index); - } - let start = parse_pos(s, i, source)?; - let end = if s.eat_if('-') { parse_pos(s, i, source)? } else { start }; - s.eat_whitespace(); - Some(start..end) -} - -/// Returns the number of lines of comment from line i to next line of code. -fn comments_until_code(source: &Source, i: usize) -> usize { - source_to_lines(source)[i..] - .iter() - .take_while(|line| line.starts_with("//")) - .count() -} - -fn source_to_lines(source: &Source) -> Vec<&str> { - source.text().lines().map(str::trim).collect() -} - -fn validate_set_annotation( - value: &str, - flag: &mut Option<bool>, - invalid_data: &mut Vec<InvalidMetadata>, -) { - let value = value.trim(); - if value != "false" && value != "true" { - invalid_data.push( - InvalidMetadata::InvalidSet(format!("Error: trying to set Ref, Hints, or Autocomplete with value {value:?} != true, != false."))) - } else { - *flag = Some(value == "true") - } -} diff --git a/tests/src/run.rs b/tests/src/run.rs new file mode 100644 index 00000000..f797147f --- /dev/null +++ b/tests/src/run.rs @@ -0,0 +1,442 @@ +use std::fmt::Write; +use std::ops::Range; +use std::path::Path; + +use ecow::eco_vec; +use tiny_skia as sk; +use typst::diag::SourceDiagnostic; +use typst::eval::Tracer; +use typst::foundations::Smart; +use typst::introspection::Meta; +use typst::layout::{Abs, Frame, FrameItem, Page, Transform}; +use typst::model::Document; +use typst::visualize::Color; +use typst::WorldExt; + +use crate::collect::{FileSize, NoteKind, Test}; +use crate::world::TestWorld; + +/// Runs a single test. +/// +/// Returns whether the test passed. +pub fn run(test: &Test) -> TestResult { + Runner::new(test).run() +} + +/// The result of running a single test. +pub struct TestResult { + /// The error log for this test. If empty, the test passed. + pub errors: String, + /// The info log for this test. + pub infos: String, + /// Whether the image was mismatched. + pub mismatched_image: bool, +} + +impl TestResult { + /// Whether the test passed. + pub fn is_ok(&self) -> bool { + self.errors.is_empty() + } +} + +/// Write a line to a log sink, defaulting to the test's error log. +macro_rules! log { + (into: $sink:expr, $($tts:tt)*) => { + writeln!($sink, $($tts)*).unwrap(); + }; + ($runner:expr, $($tts:tt)*) => { + writeln!(&mut $runner.result.errors, $($tts)*).unwrap(); + }; +} + +/// Runs a single test. +pub struct Runner<'a> { + test: &'a Test, + world: TestWorld, + seen: Vec<bool>, + result: TestResult, + not_annotated: String, +} + +impl<'a> Runner<'a> { + /// Create a new test runner. + fn new(test: &'a Test) -> Self { + Self { + test, + world: TestWorld::new(test.source.clone()), + seen: vec![false; test.notes.len()], + result: TestResult { + errors: String::new(), + infos: String::new(), + mismatched_image: false, + }, + not_annotated: String::new(), + } + } + + /// Run the test. + fn run(mut self) -> TestResult { + if crate::ARGS.syntax { + log!(into: self.result.infos, "tree: {:#?}", self.test.source.root()); + } + + let mut tracer = Tracer::new(); + let (doc, errors) = match typst::compile(&self.world, &mut tracer) { + Ok(doc) => (Some(doc), eco_vec![]), + Err(errors) => (None, errors), + }; + + let warnings = tracer.warnings(); + if doc.is_none() && errors.is_empty() { + log!(self, "no document, but also no errors"); + } + + self.check_document(doc.as_ref()); + + for error in &errors { + self.check_diagnostic(NoteKind::Error, error); + } + + for warning in &warnings { + self.check_diagnostic(NoteKind::Warning, warning); + } + + self.handle_not_emitted(); + self.handle_not_annotated(); + + self.result + } + + /// Handle errors that weren't annotated. + fn handle_not_annotated(&mut self) { + if !self.not_annotated.is_empty() { + log!(self, "not annotated"); + self.result.errors.push_str(&self.not_annotated); + } + } + + /// Handle notes that weren't handled before. + fn handle_not_emitted(&mut self) { + let mut first = true; + for (note, &seen) in self.test.notes.iter().zip(&self.seen) { + if seen { + continue; + } + let note_range = self.format_range(¬e.range); + if first { + log!(self, "not emitted"); + first = false; + } + log!(self, " {}: {note_range} {} ({})", note.kind, note.message, note.pos,); + } + } + + /// Check that the document output is correct. + fn check_document(&mut self, document: Option<&Document>) { + let live_path = format!("{}/render/{}.png", crate::STORE_PATH, self.test.name); + let ref_path = format!("{}/{}.png", crate::REF_PATH, self.test.name); + let has_ref = Path::new(&ref_path).exists(); + + let Some(document) = document else { + if has_ref { + log!(self, "missing document"); + log!(self, " ref | {ref_path}"); + } + return; + }; + + let skippable = match document.pages.as_slice() { + [page] => skippable(page), + _ => false, + }; + + // Tests without visible output and no reference image don't need to be + // compared. + if skippable && !has_ref { + std::fs::remove_file(&live_path).ok(); + return; + } + + // Render the live version. + let pixmap = render(document, 1.0); + + // Save live version, possibly rerendering if different scale is + // requested. + let mut pixmap_live = &pixmap; + let slot; + let scale = crate::ARGS.scale; + if scale != 1.0 { + slot = render(document, scale); + pixmap_live = &slot; + } + let data = pixmap_live.encode_png().unwrap(); + std::fs::write(&live_path, data).unwrap(); + + // Write PDF if requested. + if crate::ARGS.pdf { + let pdf_path = format!("{}/pdf/{}.pdf", crate::STORE_PATH, self.test.name); + let pdf = typst_pdf::pdf(document, Smart::Auto, None); + std::fs::write(pdf_path, pdf).unwrap(); + } + + // Write SVG if requested. + if crate::ARGS.svg { + let svg_path = format!("{}/svg/{}.svg", crate::STORE_PATH, self.test.name); + let svg = typst_svg::svg_merged(document, Abs::pt(5.0)); + std::fs::write(svg_path, svg).unwrap(); + } + + // Compare against reference image if available. + let equal = has_ref && { + let ref_data = std::fs::read(&ref_path).unwrap(); + let ref_pixmap = sk::Pixmap::decode_png(&ref_data).unwrap(); + approx_equal(&pixmap, &ref_pixmap) + }; + + // Test that is ok doesn't need to be updated. + if equal { + return; + } + + if crate::ARGS.update { + if skippable { + std::fs::remove_file(&ref_path).unwrap(); + log!( + into: self.result.infos, + "removed reference image ({ref_path})" + ); + } else { + let opts = oxipng::Options::max_compression(); + let data = pixmap.encode_png().unwrap(); + let ref_data = oxipng::optimize_from_memory(&data, &opts).unwrap(); + if !self.test.large && ref_data.len() > crate::REF_LIMIT { + log!(self, "reference image would exceed maximum size"); + log!(self, " maximum | {}", FileSize(crate::REF_LIMIT)); + log!(self, " size | {}", FileSize(ref_data.len())); + log!(self, "please try to minimize the size of the test (smaller pages, less text, etc.)"); + log!(self, "if you think the test cannot be reasonably minimized, mark it as `// LARGE`"); + return; + } + std::fs::write(&ref_path, &ref_data).unwrap(); + log!( + into: self.result.infos, + "Updated reference image ({ref_path}, {})", + FileSize(ref_data.len()), + ); + } + } else { + self.result.mismatched_image = true; + if has_ref { + log!(self, "mismatched rendering"); + log!(self, " live | {live_path}"); + log!(self, " ref | {ref_path}"); + } else { + log!(self, "missing reference image"); + log!(self, " live | {live_path}"); + } + } + } + + /// Compare a subset of notes with a given kind against diagnostics of + /// that same kind. + fn check_diagnostic(&mut self, kind: NoteKind, diag: &SourceDiagnostic) { + // Ignore diagnostics from other sources than the test file itself. + if diag.span.id().is_some_and(|id| id != self.test.source.id()) { + return; + } + + let message = diag.message.replace("\\", "/"); + let range = self.world.range(diag.span); + self.validate_note(kind, range.clone(), &message); + + // Check hints. + for hint in &diag.hints { + self.validate_note(NoteKind::Hint, range.clone(), hint); + } + } + + /// Try to find a matching note for the given `kind`, `range`, and + /// `message`. + /// + /// - If found, marks it as seen and returns it. + /// - If none was found, emits a "Not annotated" error and returns nothing. + fn validate_note( + &mut self, + kind: NoteKind, + range: Option<Range<usize>>, + message: &str, + ) { + // Try to find perfect match. + if let Some((i, _)) = self.test.notes.iter().enumerate().find(|&(i, note)| { + !self.seen[i] + && note.kind == kind + && note.range == range + && note.message == message + }) { + self.seen[i] = true; + return; + } + + // Try to find closely matching annotation. If the note has the same + // range or message, it's most likely the one we're interested in. + let Some((i, note)) = self.test.notes.iter().enumerate().find(|&(i, note)| { + !self.seen[i] + && note.kind == kind + && (note.range == range || note.message == message) + }) else { + // Not even a close match, diagnostic is not annotated. + let diag_range = self.format_range(&range); + log!(into: self.not_annotated, " {kind}: {diag_range} {}", message); + return; + }; + + // Mark this annotation as visited and return it. + self.seen[i] = true; + + // Range is wrong. + if range != note.range { + let note_range = self.format_range(¬e.range); + let note_text = self.text_for_range(¬e.range); + let diag_range = self.format_range(&range); + let diag_text = self.text_for_range(&range); + log!(self, "mismatched range ({}):", note.pos); + log!(self, " message | {}", note.message); + log!(self, " annotated | {note_range:<9} | {note_text}"); + log!(self, " emitted | {diag_range:<9} | {diag_text}"); + } + + // Message is wrong. + if message != note.message { + log!(self, "mismatched message ({}):", note.pos); + log!(self, " annotated | {}", note.message); + log!(self, " emitted | {message}"); + } + } + + /// Display the text for a range. + fn text_for_range(&self, range: &Option<Range<usize>>) -> String { + let Some(range) = range else { return "No text".into() }; + if range.is_empty() { + "(empty)".into() + } else { + format!("`{}`", self.test.source.text()[range.clone()].replace('\n', "\\n")) + } + } + + /// Display a byte range as a line:column range. + fn format_range(&self, range: &Option<Range<usize>>) -> String { + let Some(range) = range else { return "No range".into() }; + if range.start == range.end { + self.format_pos(range.start) + } else { + format!("{}-{}", self.format_pos(range.start,), self.format_pos(range.end,)) + } + } + + /// Display a position as a line:column pair. + fn format_pos(&self, pos: usize) -> String { + if let (Some(line_idx), Some(column_idx)) = + (self.test.source.byte_to_line(pos), self.test.source.byte_to_column(pos)) + { + let line = self.test.pos.line + line_idx; + let column = column_idx + 1; + if line == 1 { + format!("{column}") + } else { + format!("{line}:{column}") + } + } else { + "oob".into() + } + } +} + +/// Draw all frames into one image with padding in between. +fn render(document: &Document, pixel_per_pt: f32) -> sk::Pixmap { + for page in &document.pages { + let limit = Abs::cm(100.0); + if page.frame.width() > limit || page.frame.height() > limit { + panic!("overlarge frame: {:?}", page.frame.size()); + } + } + + let gap = Abs::pt(1.0); + let mut pixmap = typst_render::render_merged( + document, + pixel_per_pt, + Color::WHITE, + gap, + Color::BLACK, + ); + + let gap = (pixel_per_pt * gap.to_pt() as f32).round(); + + let mut y = 0.0; + for page in &document.pages { + let ts = + sk::Transform::from_scale(pixel_per_pt, pixel_per_pt).post_translate(0.0, y); + render_links(&mut pixmap, ts, &page.frame); + y += (pixel_per_pt * page.frame.height().to_pt() as f32).round().max(1.0) + gap; + } + + pixmap +} + +/// Draw extra boxes for links so we can see whether they are there. +fn render_links(canvas: &mut sk::Pixmap, ts: sk::Transform, frame: &Frame) { + for (pos, item) in frame.items() { + let ts = ts.pre_translate(pos.x.to_pt() as f32, pos.y.to_pt() as f32); + match *item { + FrameItem::Group(ref group) => { + let ts = ts.pre_concat(to_sk_transform(&group.transform)); + render_links(canvas, ts, &group.frame); + } + FrameItem::Meta(Meta::Link(_), size) => { + let w = size.x.to_pt() as f32; + let h = size.y.to_pt() as f32; + let rect = sk::Rect::from_xywh(0.0, 0.0, w, h).unwrap(); + let mut paint = sk::Paint::default(); + paint.set_color_rgba8(40, 54, 99, 40); + canvas.fill_rect(rect, &paint, ts, None); + } + _ => {} + } + } +} + +/// Whether rendering of a frame can be skipped. +fn skippable(page: &Page) -> bool { + page.frame.width().approx_eq(Abs::pt(120.0)) + && page.frame.height().approx_eq(Abs::pt(20.0)) + && skippable_frame(&page.frame) +} + +/// Whether rendering of a frame can be skipped. +fn skippable_frame(frame: &Frame) -> bool { + frame.items().all(|(_, item)| match item { + FrameItem::Group(group) => skippable_frame(&group.frame), + FrameItem::Meta(..) => true, + _ => false, + }) +} + +/// Whether to pixel images are approximately equal. +fn approx_equal(a: &sk::Pixmap, b: &sk::Pixmap) -> bool { + a.width() == b.width() + && a.height() == b.height() + && a.data().iter().zip(b.data()).all(|(&a, &b)| a.abs_diff(b) <= 1) +} + +/// Convert a Typst transform to a tiny-skia transform. +fn to_sk_transform(transform: &Transform) -> sk::Transform { + let Transform { sx, ky, kx, sy, tx, ty } = *transform; + sk::Transform::from_row( + sx.get() as _, + ky.get() as _, + kx.get() as _, + sy.get() as _, + tx.to_pt() as f32, + ty.to_pt() as f32, + ) +} diff --git a/tests/src/tests.rs b/tests/src/tests.rs index e4f60bb6..6d58e969 100644 --- a/tests/src/tests.rs +++ b/tests/src/tests.rs @@ -1,1127 +1,112 @@ -/*! This is Typst's test runner. +//! Typst's test runner. -Tests are Typst files composed of a header part followed by subtests. +mod args; +mod collect; +mod logger; +mod run; +mod world; -The header may contain: -- a small description `// tests that features X works well` -- metadata (see [metadata::TestConfiguration]) - -The subtests may use extra testing functions defined in [library], most -importantly, `test(x, y)` which will fail the test `if x != y`. -*/ - -#![allow(clippy::comparison_chain)] -mod metadata; - -use self::metadata::*; - -use std::borrow::Cow; -use std::collections::{HashMap, HashSet}; -use std::ffi::OsStr; -use std::fmt::Write as _; -use std::io::{self, IsTerminal, Write as _}; -use std::ops::Range; -use std::path::{Path, PathBuf, MAIN_SEPARATOR_STR}; -use std::sync::{OnceLock, RwLock}; -use std::{env, fs}; +use std::path::Path; +use std::time::Duration; use clap::Parser; -use comemo::{Prehashed, Track}; -use oxipng::{InFile, Options, OutFile}; +use once_cell::sync::Lazy; +use parking_lot::Mutex; use rayon::iter::{ParallelBridge, ParallelIterator}; -use tiny_skia as sk; -use typst::diag::{bail, FileError, FileResult, Severity, SourceDiagnostic, StrResult}; -use typst::eval::Tracer; -use typst::foundations::{func, Bytes, Datetime, NoneValue, Repr, Smart, Value}; -use typst::introspection::Meta; -use typst::layout::{Abs, Frame, FrameItem, Margin, Page, PageElem, Transform}; -use typst::model::Document; -use typst::syntax::{FileId, Source, SyntaxNode, VirtualPath}; -use typst::text::{Font, FontBook, TextElem, TextSize}; -use typst::visualize::Color; -use typst::{Library, World, WorldExt}; -use walkdir::WalkDir; -// These directories are all relative to the tests/ directory. -const TYP_DIR: &str = "typ"; -const REF_DIR: &str = "ref"; -const PNG_DIR: &str = "png"; -const PDF_DIR: &str = "pdf"; -const SVG_DIR: &str = "svg"; +use crate::args::{CliArguments, Command}; +use crate::logger::Logger; -/// Arguments that modify test behaviour. -/// -/// Specify them like this when developing: -/// `cargo test --workspace --test tests -- --help` -#[derive(Debug, Clone, Parser)] -#[clap(name = "typst-test", author)] -struct Args { - /// All the tests that contains a filter string will be run (unless - /// `--exact` is specified, which is even stricter). - filter: Vec<String>, - /// Runs only the specified subtest. - #[arg(short, long)] - #[arg(allow_hyphen_values = true)] - subtest: Option<isize>, - /// Runs only the test with the exact name specified in your command. - /// - /// Example: - /// `cargo test --workspace --test tests -- compiler/bytes.typ --exact` - #[arg(long)] - exact: bool, - /// Updates the reference images in `tests/ref`. - #[arg(long, default_value_t = env::var_os("UPDATE_EXPECT").is_some())] - update: bool, - /// Exports the tests as PDF into `tests/pdf`. - #[arg(long)] - pdf: bool, - /// Configuration of what to print. - #[command(flatten)] - print: PrintConfig, - /// Running `cargo test --workspace -- --nocapture` for the unit tests would - /// fail the test runner without argument. - // TODO: would it really still happen? - #[arg(long)] - nocapture: bool, - /// Prevents the terminal from being cleared of test names and includes - /// non-essential test messages. - #[arg(short, long)] - verbose: bool, -} +/// The parsed command line arguments. +static ARGS: Lazy<CliArguments> = Lazy::new(CliArguments::parse); -/// Which things to print out for debugging. -#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Parser)] -struct PrintConfig { - /// Print the syntax tree. - #[arg(long)] - syntax: bool, - /// Print the content model. - #[arg(long)] - model: bool, - /// Print the layouted frames. - #[arg(long)] - frames: bool, -} +/// The directory where the test suite is located. +const SUITE_PATH: &str = "tests/suite"; -impl Args { - fn matches(&self, canonicalized_path: &Path) -> bool { - let path = canonicalized_path.to_string_lossy(); - if !self.exact { - return self.filter.is_empty() - || self.filter.iter().any(|v| path.contains(v)); - } +/// The directory where the full test results are stored. +const STORE_PATH: &str = "tests/store"; - self.filter.iter().any(|v| match path.strip_suffix(v) { - None => false, - Some(residual) => { - residual.is_empty() || residual.ends_with(MAIN_SEPARATOR_STR) - } - }) - } -} - -/// Tests all test files and prints a summary. -fn main() { - let args = Args::parse(); - - // Create loader and context. - let world = TestWorld::new(args.print); - - println!("Running tests..."); - let results = WalkDir::new(TYP_DIR) - .sort_by_file_name() - .into_iter() - .par_bridge() - .filter_map(|entry| { - let entry = entry.unwrap(); - if entry.depth() == 0 { - return None; - } +/// The directory where the reference images are stored. +const REF_PATH: &str = "tests/ref"; - if entry.path().starts_with("typ/benches") { - return None; - } - - let src_path = entry.into_path(); // Relative to TYP_DIR. - if src_path.extension() != Some(OsStr::new("typ")) { - return None; - } - - if args.matches(&src_path.canonicalize().unwrap()) { - Some(src_path) - } else { - None - } - }) - .map_with(world, |world, src_path| { - let path = src_path.strip_prefix(TYP_DIR).unwrap(); - let png_path = Path::new(PNG_DIR).join(path).with_extension("png"); - let ref_path = Path::new(REF_DIR).join(path).with_extension("png"); - let svg_path = Path::new(SVG_DIR).join(path).with_extension("svg"); - let pdf_path = - args.pdf.then(|| Path::new(PDF_DIR).join(path).with_extension("pdf")); - - test( - world, - &src_path, - &png_path, - &ref_path, - pdf_path.as_deref(), - &svg_path, - &args, - ) as usize - }) - .collect::<Vec<_>>(); - - let len = results.len(); - let ok = results.iter().sum::<usize>(); - if len > 0 { - println!("{ok} / {len} test{} passed.", if len > 1 { "s" } else { "" }); - } else { - println!("No test ran."); - } - - if ok != len { - println!( - "Set the UPDATE_EXPECT environment variable or pass the \ - --update flag to update the reference image(s)." - ); - } - - if ok < len { - std::process::exit(1); - } -} +/// The maximum size of reference images that aren't marked as `// LARGE`. +const REF_LIMIT: usize = 20 * 1024; -fn library() -> Library { - #[func] - fn test(lhs: Value, rhs: Value) -> StrResult<NoneValue> { - if lhs != rhs { - bail!("Assertion failed: {} != {}", lhs.repr(), rhs.repr()); - } - Ok(NoneValue) - } - - #[func] - fn test_repr(lhs: Value, rhs: Value) -> StrResult<NoneValue> { - if lhs.repr() != rhs.repr() { - bail!("Assertion failed: {} != {}", lhs.repr(), rhs.repr()); - } - Ok(NoneValue) - } - - #[func] - fn print(#[variadic] values: Vec<Value>) -> NoneValue { - let mut stdout = io::stdout().lock(); - write!(stdout, "> ").unwrap(); - for (i, value) in values.into_iter().enumerate() { - if i > 0 { - write!(stdout, ", ").unwrap(); - } - write!(stdout, "{value:?}").unwrap(); - } - writeln!(stdout).unwrap(); - NoneValue - } - - // Set page width to 120pt with 10pt margins, so that the inner page is - // exactly 100pt wide. Page height is unbounded and font size is 10pt so - // that it multiplies to nice round numbers. - let mut lib = Library::default(); - lib.styles - .set(PageElem::set_width(Smart::Custom(Abs::pt(120.0).into()))); - lib.styles.set(PageElem::set_height(Smart::Auto)); - lib.styles.set(PageElem::set_margin(Margin::splat(Some(Smart::Custom( - Abs::pt(10.0).into(), - ))))); - lib.styles.set(TextElem::set_size(TextSize(Abs::pt(10.0).into()))); - - // Hook up helpers into the global scope. - lib.global.scope_mut().define_func::<test>(); - lib.global.scope_mut().define_func::<test_repr>(); - lib.global.scope_mut().define_func::<print>(); - lib.global - .scope_mut() - .define("conifer", Color::from_u8(0x9f, 0xEB, 0x52, 0xFF)); - lib.global - .scope_mut() - .define("forest", Color::from_u8(0x43, 0xA1, 0x27, 0xFF)); - - lib -} - -/// A world that provides access to the tests environment. -struct TestWorld { - print: PrintConfig, - main: FileId, - library: Prehashed<Library>, - book: Prehashed<FontBook>, - fonts: Vec<Font>, - slots: RwLock<HashMap<FileId, FileSlot>>, -} - -#[derive(Clone)] -struct FileSlot { - source: OnceLock<FileResult<Source>>, - buffer: OnceLock<FileResult<Bytes>>, -} - -impl TestWorld { - fn new(print: PrintConfig) -> Self { - let fonts: Vec<_> = typst_assets::fonts() - .chain(typst_dev_assets::fonts()) - .flat_map(|data| Font::iter(Bytes::from_static(data))) - .collect(); - - Self { - print, - main: FileId::new(None, VirtualPath::new("main.typ")), - library: Prehashed::new(library()), - book: Prehashed::new(FontBook::from_fonts(&fonts)), - fonts, - slots: RwLock::new(HashMap::new()), - } - } -} - -impl World for TestWorld { - fn library(&self) -> &Prehashed<Library> { - &self.library - } - - fn book(&self) -> &Prehashed<FontBook> { - &self.book - } - - fn main(&self) -> Source { - self.source(self.main).unwrap() - } - - fn source(&self, id: FileId) -> FileResult<Source> { - self.slot(id, |slot| { - slot.source - .get_or_init(|| { - let buf = read(&system_path(id)?)?; - let text = String::from_utf8(buf.into_owned())?; - Ok(Source::new(id, text)) - }) - .clone() - }) - } - - fn file(&self, id: FileId) -> FileResult<Bytes> { - self.slot(id, |slot| { - slot.buffer - .get_or_init(|| { - read(&system_path(id)?).map(|cow| match cow { - Cow::Owned(buf) => buf.into(), - Cow::Borrowed(buf) => Bytes::from_static(buf), - }) - }) - .clone() - }) - } - - fn font(&self, id: usize) -> Option<Font> { - Some(self.fonts[id].clone()) - } - - fn today(&self, _: Option<i64>) -> Option<Datetime> { - Some(Datetime::from_ymd(1970, 1, 1).unwrap()) - } -} - -impl TestWorld { - fn set(&mut self, path: &Path, text: String) -> Source { - self.main = FileId::new(None, VirtualPath::new(path)); - let source = Source::new(self.main, text); - self.slot(self.main, |slot| { - slot.source = OnceLock::from(Ok(source.clone())); - source - }) - } - - fn slot<F, T>(&self, id: FileId, f: F) -> T - where - F: FnOnce(&mut FileSlot) -> T, - { - f(self.slots.write().unwrap().entry(id).or_insert_with(|| FileSlot { - source: OnceLock::new(), - buffer: OnceLock::new(), - })) - } -} +fn main() { + setup(); -impl Clone for TestWorld { - fn clone(&self) -> Self { - Self { - print: self.print, - main: self.main, - library: self.library.clone(), - book: self.book.clone(), - fonts: self.fonts.clone(), - slots: RwLock::new(self.slots.read().unwrap().clone()), - } + match &ARGS.command { + None => test(), + Some(Command::Clean) => std::fs::remove_dir_all(STORE_PATH).unwrap(), } } -/// The file system path for a file ID. -fn system_path(id: FileId) -> FileResult<PathBuf> { - let root: PathBuf = match id.package() { - Some(spec) => format!("packages/{}-{}", spec.name, spec.version).into(), - None => PathBuf::new(), - }; - - id.vpath().resolve(&root).ok_or(FileError::AccessDenied) -} - -/// Read a file. -fn read(path: &Path) -> FileResult<Cow<'static, [u8]>> { - // Basically symlinks `assets/files` to `tests/files` so that the assets - // are within the test project root. - let resolved = path.to_path_buf(); - if let Ok(suffix) = path.strip_prefix("assets/") { - return typst_dev_assets::get(&suffix.to_string_lossy()) - .map(Cow::Borrowed) - .ok_or_else(|| FileError::NotFound(path.into())); - } - - let f = |e| FileError::from_io(e, path); - if fs::metadata(&resolved).map_err(f)?.is_dir() { - Err(FileError::IsDirectory) - } else { - fs::read(&resolved).map(Cow::Owned).map_err(f) - } -} +fn setup() { + // Make all paths relative to the workspace. That's nicer for IDEs when + // clicking on paths printed to the terminal. + std::env::set_current_dir("..").unwrap(); -/// Tests a test file and prints the result. -/// -/// Also tests that the header of each test is written correctly. -/// See [parse_part_metadata] for more details. -fn test( - world: &mut TestWorld, - src_path: &Path, - png_path: &Path, - ref_path: &Path, - pdf_path: Option<&Path>, - svg_path: &Path, - args: &Args, -) -> bool { - struct PanicGuard<'a>(&'a Path); - impl Drop for PanicGuard<'_> { - fn drop(&mut self) { - if std::thread::panicking() { - println!("Panicked in {}", self.0.display()); - } - } + // Create the storage. + for ext in ["render", "pdf", "svg"] { + std::fs::create_dir_all(Path::new(STORE_PATH).join(ext)).unwrap(); } - let name = src_path.strip_prefix(TYP_DIR).unwrap_or(src_path); - let text = fs::read_to_string(src_path).unwrap(); - let _guard = PanicGuard(name); - - let mut output = String::new(); - let mut ok = true; - let mut updated = false; - let mut pages = vec![]; - let mut line = 0; - let mut header_configuration = None; - let mut compare_ever = false; - let mut rng = LinearShift::new(); - - let parts: Vec<_> = text - .split("\n---") - .map(|s| s.strip_suffix('\r').unwrap_or(s)) - .collect(); - - for (i, &part) in parts.iter().enumerate() { - if let Some(x) = args.subtest { - let x = usize::try_from( - x.rem_euclid(isize::try_from(parts.len()).unwrap_or_default()), - ) + // Set up the thread pool. + if let Some(num_threads) = ARGS.num_threads { + rayon::ThreadPoolBuilder::new() + .num_threads(num_threads) + .build_global() .unwrap(); - if x != i { - writeln!(output, " Skipped subtest {i}.").unwrap(); - continue; - } - } - let is_header = i == 0 - && parts.len() > 1 - && part - .lines() - .all(|s| s.starts_with("//") || s.chars().all(|c| c.is_whitespace())); - - if is_header { - let source = Source::detached(part.to_string()); - let metadata = parse_part_metadata(&source, true); - match metadata { - Ok(metadata) => { - header_configuration = Some(metadata.config); - } - Err(invalid_data) => { - ok = false; - writeln!( - output, - " Test {}: invalid metadata in header, failing the test:", - name.display() - ) - .unwrap(); - InvalidMetadata::write( - invalid_data, - &mut output, - &mut |annotation, output| { - print_annotation(output, &source, line, annotation) - }, - ); - } - } - } else { - let (part_ok, compare_here, part_frames) = test_part( - &mut output, - world, - src_path, - part.into(), - line, - i, - header_configuration.as_ref().unwrap_or(&Default::default()), - &mut rng, - args.verbose, - ); - - ok &= part_ok; - compare_ever |= compare_here; - pages.extend(part_frames); - } - - line += part.lines().count() + 1; - } - - let document = Document { pages, ..Default::default() }; - if compare_ever { - if let Some(pdf_path) = pdf_path { - let pdf_data = typst_pdf::pdf( - &document, - Smart::Custom(&format!("typst-test: {}", name.display())), - world.today(Some(0)), - ); - fs::create_dir_all(pdf_path.parent().unwrap()).unwrap(); - fs::write(pdf_path, pdf_data).unwrap(); - } - - if world.print.frames { - for frame in &document.pages { - writeln!(output, "{frame:#?}\n").unwrap(); - } - } - - let canvas = render(&document); - fs::create_dir_all(png_path.parent().unwrap()).unwrap(); - canvas.save_png(png_path).unwrap(); - - let svg = typst_svg::svg_merged(&document, Abs::pt(5.0)); - - fs::create_dir_all(svg_path.parent().unwrap()).unwrap(); - std::fs::write(svg_path, svg.as_bytes()).unwrap(); - - if let Ok(ref_pixmap) = sk::Pixmap::load_png(ref_path) { - if canvas.width() != ref_pixmap.width() - || canvas.height() != ref_pixmap.height() - || canvas - .data() - .iter() - .zip(ref_pixmap.data()) - .any(|(&a, &b)| a.abs_diff(b) > 2) - { - if args.update { - update_image(png_path, ref_path); - updated = true; - } else { - writeln!(output, " Does not match reference image.").unwrap(); - ok = false; - } - } - } else if !document.pages.is_empty() { - if args.update { - update_image(png_path, ref_path); - updated = true; - } else { - writeln!(output, " Failed to open reference image.").unwrap(); - ok = false; - } - } } - - { - let mut stdout = io::stdout().lock(); - stdout.write_all(name.to_string_lossy().as_bytes()).unwrap(); - if ok { - writeln!(stdout, " ✔").unwrap(); - // Don't clear the line when in verbose mode or when the reference image - // was updated, to show in the output which test had its image updated. - if !updated && !args.verbose && stdout.is_terminal() { - // ANSI escape codes: cursor moves up and clears the line. - write!(stdout, "\x1b[1A\x1b[2K").unwrap(); - } - } else { - writeln!(stdout, " ❌").unwrap(); - } - if updated { - writeln!(stdout, " Updated reference image.").unwrap(); - } - if !output.is_empty() { - stdout.write_all(output.as_bytes()).unwrap(); - } - } - - ok } -fn update_image(png_path: &Path, ref_path: &Path) { - oxipng::optimize( - &InFile::Path(png_path.to_owned()), - &OutFile::from_path(ref_path.to_owned()), - &Options::max_compression(), - ) - .unwrap(); -} - -#[allow(clippy::too_many_arguments)] -fn test_part( - output: &mut String, - world: &mut TestWorld, - src_path: &Path, - text: String, - line: usize, - i: usize, - header_configuration: &TestConfig, - rng: &mut LinearShift, - verbose: bool, -) -> (bool, bool, Vec<Page>) { - let source = world.set(src_path, text); - if world.print.syntax { - writeln!(output, "Syntax Tree:\n{:#?}\n", source.root()).unwrap(); - } - - if world.print.model { - print_model(world, &source, output); - } - - let mut tracer = Tracer::new(); - let (mut frames, diagnostics) = match typst::compile(world, &mut tracer) { - Ok(document) => (document.pages, tracer.warnings()), +fn test() { + let (tests, skipped) = match crate::collect::collect() { + Ok(output) => output, Err(errors) => { - let mut warnings = tracer.warnings(); - warnings.extend(errors); - (vec![], warnings) - } - }; - - let metadata = parse_part_metadata(&source, false); - match metadata { - Ok(metadata) => { - let mut ok = true; - let compare_ref = metadata - .config - .compare_ref - .unwrap_or(header_configuration.compare_ref.unwrap_or(true)); - let validate_hints = metadata - .config - .validate_hints - .unwrap_or(header_configuration.validate_hints.unwrap_or(true)); - let validate_autocomplete = metadata - .config - .validate_autocomplete - .unwrap_or(header_configuration.validate_autocomplete.unwrap_or(false)); - - if verbose { - writeln!(output, "Subtest {i} runs with compare_ref={compare_ref}; validate_hints={validate_hints}; validate_autocomplete={validate_autocomplete};").unwrap(); - } - ok &= test_spans(output, source.root()); - ok &= test_reparse(output, source.text(), i, rng); - - // Don't retain frames if we don't want to compare with reference images. - if !compare_ref { - frames.clear(); - } - - // we never check autocomplete and error at the same time - - let diagnostic_annotations = metadata - .annotations - .iter() - .filter(|a| { - !matches!( - a.kind, - AnnotationKind::AutocompleteContains - | AnnotationKind::AutocompleteExcludes - ) - }) - .cloned() - .collect::<HashSet<_>>(); - - if validate_autocomplete { - // warns and ignores diagnostics - if !diagnostic_annotations.is_empty() { - writeln!( - output, - " Subtest {i} contains diagnostics but is in autocomplete mode." - ) - .unwrap(); - for annotation in diagnostic_annotations { - write!(output, " Ignored | ").unwrap(); - print_annotation(output, &source, line, &annotation); - } - } - - test_autocomplete( - output, - world, - &source, - line, - i, - &mut ok, - metadata.annotations.iter(), - ); - } else { - test_diagnostics( - output, - world, - &source, - line, - i, - &mut ok, - validate_hints, - diagnostics.iter(), - &diagnostic_annotations, - ); - } - - (ok, compare_ref, frames) - } - Err(invalid_data) => { - writeln!(output, " Subtest {i} has invalid metadata, failing the test:") - .unwrap(); - InvalidMetadata::write( - invalid_data, - output, - &mut |annotation: &Annotation, output: &mut String| { - print_annotation(output, &source, line, annotation) - }, - ); - - (false, false, frames) - } - } -} - -#[allow(clippy::too_many_arguments)] -fn test_autocomplete<'a>( - output: &mut String, - world: &mut TestWorld, - source: &Source, - line: usize, - i: usize, - ok: &mut bool, - annotations: impl Iterator<Item = &'a Annotation>, -) { - for annotation in annotations.filter(|a| { - matches!( - a.kind, - AnnotationKind::AutocompleteContains | AnnotationKind::AutocompleteExcludes - ) - }) { - // Ok cause we checked in parsing that range was Some for this annotation - let cursor = annotation.range.as_ref().unwrap().start; - - // todo, use document if is_some to test labels autocomplete - let completions = typst_ide::autocomplete(world, None, source, cursor, true) - .map(|(_, c)| c) - .unwrap_or_default() - .into_iter() - .map(|c| c.label.to_string()) - .collect::<HashSet<_>>(); - let completions = - completions.iter().map(|s| s.as_str()).collect::<HashSet<&str>>(); - - let must_contain_or_exclude = parse_string_list(&annotation.text); - let missing = - must_contain_or_exclude.difference(&completions).collect::<Vec<_>>(); - - if !missing.is_empty() - && matches!(annotation.kind, AnnotationKind::AutocompleteContains) - { - writeln!(output, " Subtest {i} does not match expected completions.") - .unwrap(); - write!(output, " for annotation | ").unwrap(); - print_annotation(output, source, line, annotation); - - write!(output, " Not contained // ").unwrap(); - for item in missing { - write!(output, "{item:?}, ").unwrap() + eprintln!("failed to collect tests"); + for error in errors { + eprintln!("❌ {error}"); } - writeln!(output).unwrap(); - *ok = false; + std::process::exit(1); } - - let undesired = - must_contain_or_exclude.intersection(&completions).collect::<Vec<_>>(); - - if !undesired.is_empty() - && matches!(annotation.kind, AnnotationKind::AutocompleteExcludes) - { - writeln!(output, " Subtest {i} does not match expected completions.") - .unwrap(); - write!(output, " for annotation | ").unwrap(); - print_annotation(output, source, line, annotation); - - write!(output, " Not excluded // ").unwrap(); - for item in undesired { - write!(output, "{item:?}, ").unwrap() - } - writeln!(output).unwrap(); - *ok = false; - } - } -} - -#[allow(clippy::too_many_arguments)] -fn test_diagnostics<'a>( - output: &mut String, - world: &mut TestWorld, - source: &Source, - line: usize, - i: usize, - ok: &mut bool, - validate_hints: bool, - diagnostics: impl Iterator<Item = &'a SourceDiagnostic>, - diagnostic_annotations: &HashSet<Annotation>, -) { - // Map diagnostics to range and message format, discard traces and errors from - // other files, collect hints. - // - // This has one caveat: due to the format of the expected hints, we can not - // verify if a hint belongs to a diagnostic or not. That should be irrelevant - // however, as the line of the hint is still verified. - let mut actual_diagnostics = HashSet::new(); - for diagnostic in diagnostics { - // Ignore diagnostics from other files. - if diagnostic.span.id().is_some_and(|id| id != source.id()) { - continue; - } - - let annotation = Annotation { - kind: match diagnostic.severity { - Severity::Error => AnnotationKind::Error, - Severity::Warning => AnnotationKind::Warning, - }, - range: world.range(diagnostic.span), - text: diagnostic.message.replace("\\", "/"), - }; - - if validate_hints { - for hint in &diagnostic.hints { - actual_diagnostics.insert(Annotation { - kind: AnnotationKind::Hint, - text: hint.clone(), - range: annotation.range.clone(), - }); - } - } - - actual_diagnostics.insert(annotation); - } - - // Basically symmetric_difference, but we need to know where an item is coming from. - let mut unexpected_outputs = actual_diagnostics - .difference(diagnostic_annotations) - .collect::<Vec<_>>(); - let mut missing_outputs = diagnostic_annotations - .difference(&actual_diagnostics) - .collect::<Vec<_>>(); - - unexpected_outputs.sort_by_key(|&v| v.range.as_ref().map(|r| r.start)); - missing_outputs.sort_by_key(|&v| v.range.as_ref().map(|r| r.start)); - - // This prints all unexpected emits first, then all missing emits. - // Is this reasonable or subject to change? - if !(unexpected_outputs.is_empty() && missing_outputs.is_empty()) { - writeln!(output, " Subtest {i} does not match expected errors.").unwrap(); - *ok = false; - - for unexpected in unexpected_outputs { - write!(output, " Not annotated // ").unwrap(); - print_annotation(output, source, line, unexpected) - } - - for missing in missing_outputs { - write!(output, " Not emitted // ").unwrap(); - print_annotation(output, source, line, missing) - } - } -} - -fn print_model(world: &mut TestWorld, source: &Source, output: &mut String) { - let world = (world as &dyn World).track(); - let route = typst::engine::Route::default(); - let mut tracer = typst::eval::Tracer::new(); - - let module = - typst::eval::eval(world, route.track(), tracer.track_mut(), source).unwrap(); - writeln!(output, "Model:\n{:#?}\n", module.content()).unwrap(); -} - -fn print_annotation( - output: &mut String, - source: &Source, - line: usize, - annotation: &Annotation, -) { - let Annotation { range, text, kind } = annotation; - write!(output, "{kind}: ").unwrap(); - if let Some(range) = range { - 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(); - write!(output, "{start_line}:{start_col}-{end_line}:{end_col} ").unwrap(); - } - writeln!(output, "{text}").unwrap(); -} - -/// Pseudorandomly edit the source file and test whether a reparse produces the -/// same result as a clean parse. -/// -/// The method will first inject 10 strings once every 400 source characters -/// and then select 5 leaf node boundaries to inject an additional, randomly -/// chosen string from the injection list. -fn test_reparse( - output: &mut String, - text: &str, - i: usize, - rng: &mut LinearShift, -) -> bool { - let supplements = [ - "[", - "]", - "{", - "}", - "(", - ")", - "#rect()", - "a word", - ", a: 1", - "10.0", - ":", - "if i == 0 {true}", - "for", - "* hello *", - "//", - "/*", - "\\u{12e4}", - "```typst", - " ", - "trees", - "\\", - "$ a $", - "2.", - "-", - "5", - ]; - - let mut ok = true; - let mut apply = |replace: Range<usize>, with| { - let mut incr_source = Source::detached(text); - if incr_source.root().len() != text.len() { - println!( - " Subtest {i} tree length {} does not match string length {} ❌", - incr_source.root().len(), - text.len(), - ); - return false; - } - - incr_source.edit(replace.clone(), with); - - let edited_src = incr_source.text(); - let ref_source = Source::detached(edited_src); - let ref_root = ref_source.root(); - let incr_root = incr_source.root(); - - // Ensures that the span numbering invariants hold. - let spans_ok = test_spans(output, ref_root) && test_spans(output, incr_root); - - // Ensure that the reference and incremental trees are the same. - let tree_ok = ref_root.spanless_eq(incr_root); - - if !tree_ok { - writeln!( - output, - " Subtest {i} reparse differs from clean parse when inserting '{with}' at {}-{} ❌\n", - replace.start, replace.end, - ).unwrap(); - writeln!(output, " Expected reference tree:\n{ref_root:#?}\n").unwrap(); - writeln!(output, " Found incremental tree:\n{incr_root:#?}").unwrap(); - writeln!( - output, - " Full source ({}):\n\"{edited_src:?}\"", - edited_src.len() - ) - .unwrap(); - } - - spans_ok && tree_ok - }; - - let mut pick = |range: Range<usize>| { - let ratio = rng.next(); - (range.start as f64 + ratio * (range.end - range.start) as f64).floor() as usize }; - let insertions = (text.len() as f64 / 400.0).ceil() as usize; - for _ in 0..insertions { - let supplement = supplements[pick(0..supplements.len())]; - let start = pick(0..text.len()); - let end = pick(start..text.len()); - - if !text.is_char_boundary(start) || !text.is_char_boundary(end) { - continue; - } - - ok &= apply(start..end, supplement); - } - - let source = Source::detached(text); - let leafs = leafs(source.root()); - let start = source.find(leafs[pick(0..leafs.len())].span()).unwrap().offset(); - let supplement = supplements[pick(0..supplements.len())]; - ok &= apply(start..start, supplement); - - ok -} - -/// Returns all leaf descendants of a node (may include itself). -fn leafs(node: &SyntaxNode) -> Vec<SyntaxNode> { - if node.children().len() == 0 { - vec![node.clone()] - } else { - node.children().flat_map(leafs).collect() - } -} - -/// Ensure that all spans are properly ordered (and therefore unique). -#[track_caller] -fn test_spans(output: &mut String, root: &SyntaxNode) -> bool { - test_spans_impl(output, root, 0..u64::MAX) -} - -#[track_caller] -fn test_spans_impl(output: &mut String, node: &SyntaxNode, within: Range<u64>) -> bool { - if !within.contains(&node.span().number()) { - writeln!(output, " Node: {node:#?}").unwrap(); - writeln!( - output, - " Wrong span order: {} not in {within:?} ❌", - node.span().number() - ) - .unwrap(); - } - - 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(output, child, start..end) { - return false; - } - } - - true -} - -/// Draw all frames into one image with padding in between. -fn render(document: &Document) -> sk::Pixmap { - let pixel_per_pt = 2.0; - let padding = Abs::pt(5.0); - - for page in &document.pages { - let limit = Abs::cm(100.0); - if page.frame.width() > limit || page.frame.height() > limit { - panic!("overlarge frame: {:?}", page.frame.size()); - } - } - - let mut pixmap = typst_render::render_merged( - document, - pixel_per_pt, - Color::WHITE, - padding, - Color::BLACK, - ); - - let padding = (pixel_per_pt * padding.to_pt() as f32).round(); - let [x, mut y] = [padding; 2]; - for page in &document.pages { - let ts = - sk::Transform::from_scale(pixel_per_pt, pixel_per_pt).post_translate(x, y); - render_links(&mut pixmap, ts, &page.frame); - y += (pixel_per_pt * page.frame.height().to_pt() as f32).round().max(1.0) - + padding; - } - - pixmap -} - -/// Draw extra boxes for links so we can see whether they are there. -fn render_links(canvas: &mut sk::Pixmap, ts: sk::Transform, frame: &Frame) { - for (pos, item) in frame.items() { - let ts = ts.pre_translate(pos.x.to_pt() as f32, pos.y.to_pt() as f32); - match *item { - FrameItem::Group(ref group) => { - let ts = ts.pre_concat(to_sk_transform(&group.transform)); - render_links(canvas, ts, &group.frame); - } - FrameItem::Meta(Meta::Link(_), size) => { - let w = size.x.to_pt() as f32; - let h = size.y.to_pt() as f32; - let rect = sk::Rect::from_xywh(0.0, 0.0, w, h).unwrap(); - let mut paint = sk::Paint::default(); - paint.set_color_rgba8(40, 54, 99, 40); - canvas.fill_rect(rect, &paint, ts, None); - } - _ => {} - } - } -} - -fn to_sk_transform(transform: &Transform) -> sk::Transform { - let Transform { sx, ky, kx, sy, tx, ty } = *transform; - sk::Transform::from_row( - sx.get() as _, - ky.get() as _, - kx.get() as _, - sy.get() as _, - tx.to_pt() as f32, - ty.to_pt() as f32, - ) -} - -/// A Linear-feedback shift register using XOR as its shifting function. -/// Can be used as PRNG. -struct LinearShift(u64); - -impl LinearShift { - /// Initialize the shift register with a pre-set seed. - pub fn new() -> Self { - Self(0xACE5) - } - - /// Return a pseudo-random number between `0.0` and `1.0`. - pub fn next(&mut self) -> f64 { - self.0 ^= self.0 >> 3; - self.0 ^= self.0 << 14; - self.0 ^= self.0 >> 28; - self.0 ^= self.0 << 36; - self.0 ^= self.0 >> 52; - self.0 as f64 / u64::MAX as f64 + let filtered = tests.len(); + if filtered == 0 { + eprintln!("no test selected"); + return; + } + + // Run the tests. + let logger = Mutex::new(Logger::new(filtered, skipped)); + std::thread::scope(|scope| { + let logger = &logger; + let (sender, receiver) = std::sync::mpsc::channel(); + + // Regularly refresh the logger in case we make no progress. + scope.spawn(move || { + while receiver.recv_timeout(Duration::from_millis(500)).is_err() { + logger.lock().refresh(); + } + }); + + // Run the tests. + // + // We use `par_bridge` instead of `par_iter` because the former + // results in a stack overflow during PDF export. Probably related + // to `typst::util::Deferred` yielding. + tests.iter().par_bridge().for_each(|test| { + logger.lock().start(test); + let result = std::panic::catch_unwind(|| run::run(test)); + logger.lock().end(test, result); + }); + + sender.send(()).unwrap(); + }); + + let passed = logger.into_inner().finish(); + if !passed { + std::process::exit(1); } } diff --git a/tests/src/world.rs b/tests/src/world.rs new file mode 100644 index 00000000..86ee8da6 --- /dev/null +++ b/tests/src/world.rs @@ -0,0 +1,229 @@ +use std::borrow::Cow; +use std::collections::HashMap; +use std::fs; +use std::io::Write; +use std::path::{Path, PathBuf}; +use std::sync::OnceLock; + +use comemo::Prehashed; +use once_cell::sync::Lazy; +use parking_lot::Mutex; +use typst::diag::{bail, FileError, FileResult, StrResult}; +use typst::foundations::{func, Bytes, Datetime, NoneValue, Repr, Smart, Value}; +use typst::layout::{Abs, Margin, PageElem}; +use typst::syntax::{FileId, Source}; +use typst::text::{Font, FontBook, TextElem, TextSize}; +use typst::visualize::Color; +use typst::{Library, World}; + +/// A world that provides access to the tests environment. +#[derive(Clone)] +pub struct TestWorld { + main: Source, + base: &'static TestBase, +} + +impl TestWorld { + /// Create a new world for a single test. + /// + /// This is cheap because the shared base for all test runs is lazily + /// initialized just once. + pub fn new(source: Source) -> Self { + static BASE: Lazy<TestBase> = Lazy::new(TestBase::default); + Self { main: source, base: &*BASE } + } +} + +impl World for TestWorld { + fn library(&self) -> &Prehashed<Library> { + &self.base.library + } + + fn book(&self) -> &Prehashed<FontBook> { + &self.base.book + } + + fn main(&self) -> Source { + self.main.clone() + } + + fn source(&self, id: FileId) -> FileResult<Source> { + if id == self.main.id() { + Ok(self.main.clone()) + } else { + self.slot(id, FileSlot::source) + } + } + + fn file(&self, id: FileId) -> FileResult<Bytes> { + self.slot(id, FileSlot::file) + } + + fn font(&self, index: usize) -> Option<Font> { + Some(self.base.fonts[index].clone()) + } + + fn today(&self, _: Option<i64>) -> Option<Datetime> { + Some(Datetime::from_ymd(1970, 1, 1).unwrap()) + } +} + +impl TestWorld { + /// Access the canonical slot for the given file id. + fn slot<F, T>(&self, id: FileId, f: F) -> T + where + F: FnOnce(&mut FileSlot) -> T, + { + let mut map = self.base.slots.lock(); + f(map.entry(id).or_insert_with(|| FileSlot::new(id))) + } +} + +/// Shared foundation of all test worlds. +struct TestBase { + library: Prehashed<Library>, + book: Prehashed<FontBook>, + fonts: Vec<Font>, + slots: Mutex<HashMap<FileId, FileSlot>>, +} + +impl Default for TestBase { + fn default() -> Self { + let fonts: Vec<_> = typst_assets::fonts() + .chain(typst_dev_assets::fonts()) + .flat_map(|data| Font::iter(Bytes::from_static(data))) + .collect(); + + Self { + library: Prehashed::new(library()), + book: Prehashed::new(FontBook::from_fonts(&fonts)), + fonts, + slots: Mutex::new(HashMap::new()), + } + } +} + +/// Holds the processed data for a file ID. +#[derive(Clone)] +struct FileSlot { + id: FileId, + source: OnceLock<FileResult<Source>>, + file: OnceLock<FileResult<Bytes>>, +} + +impl FileSlot { + /// Create a new file slot. + fn new(id: FileId) -> Self { + Self { id, file: OnceLock::new(), source: OnceLock::new() } + } + + /// Retrieve the source for this file. + fn source(&mut self) -> FileResult<Source> { + self.source + .get_or_init(|| { + let buf = read(&system_path(self.id)?)?; + let text = String::from_utf8(buf.into_owned())?; + Ok(Source::new(self.id, text)) + }) + .clone() + } + + /// Retrieve the file's bytes. + fn file(&mut self) -> FileResult<Bytes> { + self.file + .get_or_init(|| { + read(&system_path(self.id)?).map(|cow| match cow { + Cow::Owned(buf) => buf.into(), + Cow::Borrowed(buf) => Bytes::from_static(buf), + }) + }) + .clone() + } +} + +/// The file system path for a file ID. +fn system_path(id: FileId) -> FileResult<PathBuf> { + let root: PathBuf = match id.package() { + Some(spec) => format!("tests/packages/{}-{}", spec.name, spec.version).into(), + None => PathBuf::new(), + }; + + id.vpath().resolve(&root).ok_or(FileError::AccessDenied) +} + +/// Read a file. +fn read(path: &Path) -> FileResult<Cow<'static, [u8]>> { + // Resolve asset. + if let Ok(suffix) = path.strip_prefix("assets/") { + return typst_dev_assets::get(&suffix.to_string_lossy()) + .map(Cow::Borrowed) + .ok_or_else(|| FileError::NotFound(path.into())); + } + + let f = |e| FileError::from_io(e, path); + if fs::metadata(path).map_err(f)?.is_dir() { + Err(FileError::IsDirectory) + } else { + fs::read(path).map(Cow::Owned).map_err(f) + } +} + +/// The extended standard library for testing. +fn library() -> Library { + // Set page width to 120pt with 10pt margins, so that the inner page is + // exactly 100pt wide. Page height is unbounded and font size is 10pt so + // that it multiplies to nice round numbers. + let mut lib = Library::default(); + + #[func] + fn test(lhs: Value, rhs: Value) -> StrResult<NoneValue> { + if lhs != rhs { + bail!("Assertion failed: {} != {}", lhs.repr(), rhs.repr()); + } + Ok(NoneValue) + } + + #[func] + fn test_repr(lhs: Value, rhs: Value) -> StrResult<NoneValue> { + if lhs.repr() != rhs.repr() { + bail!("Assertion failed: {} != {}", lhs.repr(), rhs.repr()); + } + Ok(NoneValue) + } + + #[func] + fn print(#[variadic] values: Vec<Value>) -> NoneValue { + let mut out = std::io::stdout().lock(); + write!(out, "> ").unwrap(); + for (i, value) in values.into_iter().enumerate() { + if i > 0 { + write!(out, ", ").unwrap(); + } + write!(out, "{value:?}").unwrap(); + } + writeln!(out).unwrap(); + NoneValue + } + + // Hook up helpers into the global scope. + lib.global.scope_mut().define_func::<test>(); + lib.global.scope_mut().define_func::<test_repr>(); + lib.global.scope_mut().define_func::<print>(); + lib.global + .scope_mut() + .define("conifer", Color::from_u8(0x9f, 0xEB, 0x52, 0xFF)); + lib.global + .scope_mut() + .define("forest", Color::from_u8(0x43, 0xA1, 0x27, 0xFF)); + + // Hook up default styles. + lib.styles + .set(PageElem::set_width(Smart::Custom(Abs::pt(120.0).into()))); + lib.styles.set(PageElem::set_height(Smart::Auto)); + lib.styles.set(PageElem::set_margin(Margin::splat(Some(Smart::Custom( + Abs::pt(10.0).into(), + ))))); + lib.styles.set(TextElem::set_size(TextSize(Abs::pt(10.0).into()))); + + lib +} diff --git a/tests/suite/foundations/array.typ b/tests/suite/foundations/array.typ new file mode 100644 index 00000000..d4a2f151 --- /dev/null +++ b/tests/suite/foundations/array.typ @@ -0,0 +1,472 @@ +// Test arrays. + +--- array-basic-syntax --- +#set page(width: 150pt) + +// Empty. +#() + +// Not an array, just a parenthesized expression. +#(1) + +// One item and trailing comma. +#(-1,) + +// No trailing comma. +#(true, false) + +// Multiple lines and items and trailing comma. +#("1" + , rgb("002") + ,) + +--- array-bad-token --- +// Error: 4-6 unexpected end of block comment +#(1*/2) + +--- array-bad-number-suffix --- +// Error: 6-8 invalid number suffix: u +#(1, 1u 2) + +--- array-leading-comma --- +// Error: 3-4 unexpected comma +#(,1) + +--- array-incomplete-pair --- +// Missing expression makes named pair incomplete, making this an empty array. +// Error: 5 expected expression +#(a:) + +--- array-named-pair --- +// Named pair after this is already identified as an array. +// Error: 6-10 expected expression, found named pair +#(1, b: 2) + +--- array-keyed-pair --- +// Keyed pair after this is already identified as an array. +// Error: 6-14 expected expression, found keyed pair +#(1, "key": 2) + +--- array-bad-conversion-from-string --- +// Error: 8-15 expected array, bytes, or version, found string +#array("hello") + +--- spread-into-array --- +// Test spreading into array and dictionary. +#{ + let l = (1, 2, 3) + let r = (5, 6, 7) + test((..l, 4, ..r), range(1, 8)) + test((..none), ()) +} + +--- spread-dict-into-array --- +// Error: 9-17 cannot spread dictionary into array +#(1, 2, ..(a: 1)) + +--- array-len --- +// Test the `len` method. +#test(().len(), 0) +#test(("A", "B", "C").len(), 3) + +--- array-at-lvalue --- +// Test lvalue and rvalue access. +#{ + let array = (1, 2) + array.at(1) += 5 + array.at(0) + test(array, (1, 8)) +} + +--- array-first-and-at-lvalue --- +// Test different lvalue method. +#{ + let array = (1, 2, 3) + array.first() = 7 + array.at(1) *= 8 + test(array, (7, 16, 3)) +} + +--- array-at-out-of-bounds --- +// Test rvalue out of bounds. +// Error: 2-17 array index out of bounds (index: 5, len: 3) and no default value was specified +#(1, 2, 3).at(5) + +--- array-at-out-of-bounds-negative --- +// Error: 2-18 array index out of bounds (index: -4, len: 3) and no default value was specified +#(1, 2, 3).at(-4) + +--- array-at-out-of-bounds-lvalue --- +// Test lvalue out of bounds. +#{ + let array = (1, 2, 3) + // Error: 3-14 array index out of bounds (index: 3, len: 3) + array.at(3) = 5 +} + +--- array-at-with-default --- +// Test default value. +#test((1, 2, 3).at(2, default: 5), 3) +#test((1, 2, 3).at(3, default: 5), 5) + +--- array-remove-with-default --- +// Test remove with default value. + +#{ + let array = (1, 2, 3) + test(array.remove(2, default: 5), 3) +} + +#{ + let array = (1, 2, 3) + test(array.remove(3, default: 5), 5) +} + +--- array-range --- +// Test the `range` function. +#test(range(4), (0, 1, 2, 3)) +#test(range(1, 4), (1, 2, 3)) +#test(range(-4, 2), (-4, -3, -2, -1, 0, 1)) +#test(range(10, 5), ()) +#test(range(10, step: 3), (0, 3, 6, 9)) +#test(range(1, 4, step: 1), (1, 2, 3)) +#test(range(1, 8, step: 2), (1, 3, 5, 7)) +#test(range(5, 2, step: -1), (5, 4, 3)) +#test(range(10, 0, step: -3), (10, 7, 4, 1)) + +--- array-range-end-missing --- +// Error: 2-9 missing argument: end +#range() + +--- array-range-float-invalid --- +// Error: 11-14 expected integer, found float +#range(1, 2.0) + +--- array-range-bad-step-type --- +// Error: 17-22 expected integer, found string +#range(4, step: "one") + +--- array-range-step-zero --- +// Error: 18-19 number must not be zero +#range(10, step: 0) + +--- array-bad-method-lvalue --- +// Test bad lvalue. +// Error: 2:3-2:14 cannot mutate a temporary value +#let array = (1, 2, 3) +#(array.len() = 4) + +--- array-unknown-method-lvalue --- +// Test bad lvalue. +// Error: 2:9-2:13 type array has no method `yolo` +#let array = (1, 2, 3) +#(array.yolo() = 4) + +--- array-negative-indices --- +// Test negative indices. +#{ + let array = (1, 2, 3, 4) + test(array.at(0), 1) + test(array.at(-1), 4) + test(array.at(-2), 3) + test(array.at(-3), 2) + test(array.at(-4), 1) +} + +--- array-first-and-last --- +// The the `first` and `last` methods. +#test((1,).first(), 1) +#test((2,).last(), 2) +#test((1, 2, 3).first(), 1) +#test((1, 2, 3).last(), 3) + +--- array-first-empty --- +// Error: 2-12 array is empty +#().first() + +--- array-last-empty --- +// Error: 2-11 array is empty +#().last() + +--- array-push-and-pop --- +// Test the `push` and `pop` methods. +#{ + let tasks = (a: (1, 2, 3), b: (4, 5, 6)) + test(tasks.at("a").pop(), 3) + tasks.b.push(7) + test(tasks.a, (1, 2)) + test(tasks.at("b"), (4, 5, 6, 7)) +} + +--- array-insert-and-remove --- +// Test the `insert` and `remove` methods. +#{ + let array = (0, 1, 2, 4, 5) + array.insert(3, 3) + test(array, range(6)) + array.remove(1) + test(array, (0, 2, 3, 4, 5)) +} + +--- array-insert-missing-index --- +// Error: 2:2-2:18 missing argument: index +#let numbers = () +#numbers.insert() + +--- array-slice --- +// Test the `slice` method. +#test((1, 2, 3, 4).slice(2), (3, 4)) +#test(range(10).slice(2, 6), (2, 3, 4, 5)) +#test(range(10).slice(4, count: 3), (4, 5, 6)) +#test(range(10).slice(-5, count: 2), (5, 6)) +#test((1, 2, 3).slice(2, -2), ()) +#test((1, 2, 3).slice(-2, 2), (2,)) +#test((1, 2, 3).slice(-3, 2), (1, 2)) +#test("ABCD".split("").slice(1, -1).join("-"), "A-B-C-D") + +--- array-slice-out-of-bounds --- +// Error: 2-30 array index out of bounds (index: 12, len: 10) +#range(10).slice(9, count: 3) + +--- array-slice-out-of-bounds-negative --- +// Error: 2-24 array index out of bounds (index: -4, len: 3) +#(1, 2, 3).slice(0, -4) + +--- array-position --- +// Test the `position` method. +#test(("Hi", "❤️", "Love").position(s => s == "❤️"), 1) +#test(("Bye", "💘", "Apart").position(s => s == "❤️"), none) +#test(("A", "B", "CDEF", "G").position(v => v.len() > 2), 2) + +--- array-filter --- +// Test the `filter` method. +#test(().filter(calc.even), ()) +#test((1, 2, 3, 4).filter(calc.even), (2, 4)) +#test((7, 3, 2, 5, 1).filter(x => x < 5), (3, 2, 1)) + +--- array-map --- +// Test the `map` method. +#test(().map(x => x * 2), ()) +#test((2, 3).map(x => x * 2), (4, 6)) + +--- array-fold --- +// Test the `fold` method. +#test(().fold("hi", grid), "hi") +#test((1, 2, 3, 4).fold(0, (s, x) => s + x), 10) + +--- array-fold-closure-without-params --- +// Error: 20-22 unexpected argument +#(1, 2, 3).fold(0, () => none) + +--- array-sum --- +// Test the `sum` method. +#test(().sum(default: 0), 0) +#test(().sum(default: []), []) +#test((1, 2, 3).sum(), 6) + +--- array-sum-empty --- +// Error: 2-10 cannot calculate sum of empty array with no default +#().sum() + +--- array-product --- +// Test the `product` method. +#test(().product(default: 0), 0) +#test(().product(default: []), []) +#test(([ab], 3).product(), [ab]*3) +#test((1, 2, 3).product(), 6) + +--- array-product-empty --- +// Error: 2-14 cannot calculate product of empty array with no default +#().product() + +--- array-rev --- +// Test the `rev` method. +#test(range(3).rev(), (2, 1, 0)) + +--- array-join --- +// Test the `join` method. +#test(().join(), none) +#test((1,).join(), 1) +#test(("a", "b", "c").join(), "abc") +#test("(" + ("a", "b", "c").join(", ") + ")", "(a, b, c)") + +--- array-join-bad-values --- +// Error: 2-22 cannot join boolean with boolean +#(true, false).join() + +--- array-join-bad-separator --- +// Error: 2-20 cannot join string with integer +#("a", "b").join(1) + +--- array-join-content --- +// Test joining content. +#([One], [Two], [Three]).join([, ], last: [ and ]). + +--- array-intersperse --- +// Test the `intersperse` method +#test(().intersperse("a"), ()) +#test((1,).intersperse("a"), (1,)) +#test((1, 2).intersperse("a"), (1, "a", 2)) +#test((1, 2, "b").intersperse("a"), (1, "a", 2, "a", "b")) + +--- array-chunks --- +// Test the `chunks` method. +#test(().chunks(10), ()) +#test((1, 2, 3).chunks(10), ((1, 2, 3),)) +#test((1, 2, 3, 4, 5, 6).chunks(3), ((1, 2, 3), (4, 5, 6))) +#test((1, 2, 3, 4, 5, 6, 7, 8).chunks(3), ((1, 2, 3), (4, 5, 6), (7, 8))) + +#test(().chunks(10, exact: true), ()) +#test((1, 2, 3).chunks(10, exact: true), ()) +#test((1, 2, 3, 4, 5, 6).chunks(3, exact: true), ((1, 2, 3), (4, 5, 6))) +#test((1, 2, 3, 4, 5, 6, 7, 8).chunks(3, exact: true), ((1, 2, 3), (4, 5, 6))) + +--- array-chunks-size-zero --- +// Error: 19-20 number must be positive +#(1, 2, 3).chunks(0) + +--- array-chunks-size-negative --- +// Error: 19-21 number must be positive +#(1, 2, 3).chunks(-5) + +--- array-sorted --- +// Test the `sorted` method. +#test(().sorted(), ()) +#test(().sorted(key: x => x), ()) +#test(((true, false) * 10).sorted(), (false,) * 10 + (true,) * 10) +#test(("it", "the", "hi", "text").sorted(), ("hi", "it", "text", "the")) +#test(("I", "the", "hi", "text").sorted(key: x => x), ("I", "hi", "text", "the")) +#test(("I", "the", "hi", "text").sorted(key: x => x.len()), ("I", "hi", "the", "text")) +#test((2, 1, 3, 10, 5, 8, 6, -7, 2).sorted(), (-7, 1, 2, 2, 3, 5, 6, 8, 10)) +#test((2, 1, 3, -10, -5, 8, 6, -7, 2).sorted(key: x => x), (-10, -7, -5, 1, 2, 2, 3, 6, 8)) +#test((2, 1, 3, -10, -5, 8, 6, -7, 2).sorted(key: x => x * x), (1, 2, 2, 3, -5, 6, -7, 8, -10)) + +--- array-sorted-key-function-positional-1 --- +// Error: 12-18 unexpected argument +#().sorted(x => x) + +--- array-zip --- +// Test the `zip` method. +#test(().zip(()), ()) +#test((1,).zip(()), ()) +#test((1,).zip((2,)), ((1, 2),)) +#test((1, 2).zip((3, 4)), ((1, 3), (2, 4))) +#test((1, 2, 3, 4).zip((5, 6)), ((1, 5), (2, 6))) +#test(((1, 2), 3).zip((4, 5)), (((1, 2), 4), (3, 5))) +#test((1, "hi").zip((true, false)), ((1, true), ("hi", false))) +#test((1, 2, 3).zip((3, 4, 5), (6, 7, 8)), ((1, 3, 6), (2, 4, 7), (3, 5, 8))) +#test(().zip((), ()), ()) +#test((1,).zip((2,), (3,)), ((1, 2, 3),)) +#test((1, 2, 3).zip(), ((1,), (2,), (3,))) +#test(array.zip(()), ()) + +--- array-enumerate --- +// Test the `enumerate` method. +#test(().enumerate(), ()) +#test(().enumerate(start: 5), ()) +#test(("a", "b", "c").enumerate(), ((0, "a"), (1, "b"), (2, "c"))) +#test(("a", "b", "c").enumerate(start: 1), ((1, "a"), (2, "b"), (3, "c"))) +#test(("a", "b", "c").enumerate(start: 42), ((42, "a"), (43, "b"), (44, "c"))) +#test(("a", "b", "c").enumerate(start: -7), ((-7, "a"), (-6, "b"), (-5, "c"))) + +--- array-dedup --- +// Test the `dedup` method. +#test(().dedup(), ()) +#test((1,).dedup(), (1,)) +#test((1, 1).dedup(), (1,)) +#test((1, 2, 1).dedup(), (1, 2)) +#test(("Jane", "John", "Eric").dedup(), ("Jane", "John", "Eric")) +#test(("Jane", "John", "Eric", "John").dedup(), ("Jane", "John", "Eric")) + +--- array-dedup-key --- +// Test the `dedup` method with the `key` argument. +#test((1, 2, 3, 4, 5, 6).dedup(key: x => calc.rem(x, 2)), (1, 2)) +#test((1, 2, 3, 4, 5, 6).dedup(key: x => calc.rem(x, 3)), (1, 2, 3)) +#test(("Hello", "World", "Hi", "There").dedup(key: x => x.len()), ("Hello", "Hi")) +#test(("Hello", "World", "Hi", "There").dedup(key: x => x.at(0)), ("Hello", "World", "There")) + +--- array-zip-positional-and-named-argument --- +// Error: 13-30 unexpected argument: val +#().zip((), val: "applicable") + +--- array-sorted-bad-key --- +// Error: 32-37 cannot divide by zero +#(1, 2, 0, 3).sorted(key: x => 5 / x) + +--- array-sorted-uncomparable --- +// Error: 2-26 cannot compare content and content +#([Hi], [There]).sorted() + +--- array-sorted-uncomparable-lengths --- +// Error: 2-26 cannot compare 3em with 2pt +#(1pt, 2pt, 3em).sorted() + +--- array-sorted-key-function-positional-2 --- +// Error: 42-52 unexpected argument +#((k: "a", v: 2), (k: "b", v: 1)).sorted(it => it.v) + +--- issue-3014-mix-array-dictionary --- +// Error: 8-17 expected expression, found named pair +#(box, fill: red) + +--- issue-3154-array-first-empty --- +#{ + let array = () + // Error: 3-16 array is empty + array.first() +} + +--- issue-3154-array-first-mutable-empty --- +#{ + let array = () + // Error: 3-16 array is empty + array.first() = 9 +} + +--- issue-3154-array-last-empty --- +#{ + let array = () + // Error: 3-15 array is empty + array.last() +} + +--- issue-3154-array-last-mutable-empty --- +#{ + let array = () + // Error: 3-15 array is empty + array.last() = 9 +} + +--- issue-3154-array-at-out-of-bounds --- +#{ + let array = (1,) + // Error: 3-14 array index out of bounds (index: 1, len: 1) and no default value was specified + array.at(1) +} + +--- issue-3154-array-at-out-of-bounds-default --- +#{ + let array = (1,) + test(array.at(1, default: 0), 0) +} + +--- issue-3154-array-at-out-of-bounds-mutable --- +#{ + let array = (1,) + // Error: 3-14 array index out of bounds (index: 1, len: 1) + array.at(1) = 9 +} + +--- issue-3154-array-at-out-of-bounds-mutable-default --- +#{ + let array = (1,) + // Error: 3-26 array index out of bounds (index: 1, len: 1) + array.at(1, default: 0) = 9 +} + +--- array-unopened --- +// Error: 2-3 unclosed delimiter +#{)} + +--- array-unclosed --- +// Error: 3-4 unclosed delimiter +#{(} diff --git a/tests/suite/foundations/assert.typ b/tests/suite/foundations/assert.typ new file mode 100644 index 00000000..5de0f387 --- /dev/null +++ b/tests/suite/foundations/assert.typ @@ -0,0 +1,40 @@ +--- assert-fail --- +// Test failing assertions. +// Error: 2-16 assertion failed +#assert(1 == 2) + +--- assert-fail-message --- +// Test failing assertions. +// Error: 2-51 assertion failed: two is smaller than one +#assert(2 < 1, message: "two is smaller than one") + +--- assert-bad-type --- +// Test failing assertions. +// Error: 9-15 expected boolean, found string +#assert("true") + +--- assert-eq-fail --- +// Test failing assertions. +// Error: 2-19 equality assertion failed: value 10 was not equal to 11 +#assert.eq(10, 11) + +--- assert-eq-fail-message --- +// Test failing assertions. +// Error: 2-55 equality assertion failed: 10 and 12 are not equal +#assert.eq(10, 12, message: "10 and 12 are not equal") + +--- assert-ne-fail --- +// Test failing assertions. +// Error: 2-19 inequality assertion failed: value 11 was equal to 11 +#assert.ne(11, 11) + +--- assert-ne-fail-message --- +// Test failing assertions. +// Error: 2-57 inequality assertion failed: must be different from 11 +#assert.ne(11, 11, message: "must be different from 11") + +--- assert-success --- +// Test successful assertions. +#assert(5 > 3) +#assert.eq(15, 15) +#assert.ne(10, 12) diff --git a/tests/suite/foundations/bytes.typ b/tests/suite/foundations/bytes.typ new file mode 100644 index 00000000..c7089278 --- /dev/null +++ b/tests/suite/foundations/bytes.typ @@ -0,0 +1,31 @@ +// Test the bytes type. + +--- bytes-basic --- +#let data = read("/assets/images/rhino.png", encoding: none) +#test(data.len(), 232243) +#test(data.slice(0, count: 5), bytes((137, 80, 78, 71, 13))) +#test(str(data.slice(1, 4)), "PNG") +#test(repr(data), "bytes(232243)") + +--- bytes-string-conversion --- +#test(str(bytes(range(0x41, 0x50))), "ABCDEFGHIJKLMNO") + +--- bytes-array-conversion --- +#test(array(bytes("Hello")), (0x48, 0x65, 0x6C, 0x6C, 0x6F)) + +--- bytes-addition --- +// Test addition and joining. +#test(bytes((1, 2)) + bytes(()), bytes((1, 2))) +#test(bytes((1, 2)) + bytes((3, 4)), bytes((1, 2, 3, 4))) +#test(bytes(()) + bytes((3, 4)), bytes((3, 4))) + +--- bytes-joining --- +#test(str({ + bytes("Hello") + bytes((0x20,)) + bytes("World") +}), "Hello World") + +--- bytes-bad-conversion-from-dict --- +// Error: 8-14 expected string, array, or bytes, found dictionary +#bytes((a: 1)) diff --git a/tests/suite/foundations/calc.typ b/tests/suite/foundations/calc.typ new file mode 100644 index 00000000..e702be9f --- /dev/null +++ b/tests/suite/foundations/calc.typ @@ -0,0 +1,261 @@ +--- calc-round --- +#test(calc.round(calc.e, digits: 2), 2.72) +#test(calc.round(calc.pi, digits: 2), 3.14) + +--- calc-abs --- +// Test the `abs` function. +#test(calc.abs(-3), 3) +#test(calc.abs(3), 3) +#test(calc.abs(-0.0), 0.0) +#test(calc.abs(0.0), -0.0) +#test(calc.abs(-3.14), 3.14) +#test(calc.abs(50%), 50%) +#test(calc.abs(-25%), 25%) + +--- cals-abs-bad-type --- +// Error: 11-22 expected integer, float, length, angle, ratio, or fraction, found string +#calc.abs("no number") + +--- calc-even-and-odd --- +// Test the `even` and `odd` functions. +#test(calc.even(2), true) +#test(calc.odd(2), false) +#test(calc.odd(-1), true) +#test(calc.even(-11), false) + +--- calc-rem --- +// Test the `rem` function. +#test(calc.rem(1, 1), 0) +#test(calc.rem(5, 3), 2) +#test(calc.rem(5, -3), 2) +#test(calc.rem(22.5, 10), 2.5) +#test(calc.rem(9, 4.5), 0) + +--- calc-rem-divisor-zero-1 --- +// Error: 14-15 divisor must not be zero +#calc.rem(5, 0) + +--- calc-rem-divisor-zero-2 --- +// Error: 16-19 divisor must not be zero +#calc.rem(3.0, 0.0) + +--- calc-div-euclid --- +// Test the `div-euclid` function. +#test(calc.div-euclid(7, 3), 2) +#test(calc.div-euclid(7, -3), -2) +#test(calc.div-euclid(-7, 3), -3) +#test(calc.div-euclid(-7, -3), 3) +#test(calc.div-euclid(2.5, 2), 1) + +--- calc-div-euclid-divisor-zero-1 --- +// Error: 21-22 divisor must not be zero +#calc.div-euclid(5, 0) + +--- calc-div-euclid-divisor-zero-2 --- +// Error: 23-26 divisor must not be zero +#calc.div-euclid(3.0, 0.0) + +--- calc-rem-euclid --- +// Test the `rem-euclid` function. +#test(calc.rem-euclid(7, 3), 1) +#test(calc.rem-euclid(7, -3), 1) +#test(calc.rem-euclid(-7, 3), 2) +#test(calc.rem-euclid(-7, -3), 2) +#test(calc.rem-euclid(2.5, 2), 0.5) + +--- calc-rem-euclid-divisor-zero-1 --- +// Error: 21-22 divisor must not be zero +#calc.rem-euclid(5, 0) + +--- calc-rem-euclid-divisor-zero-2 --- +// Error: 23-26 divisor must not be zero +#calc.rem-euclid(3.0, 0.0) + +--- calc-quo --- +// Test the `quo` function. +#test(calc.quo(1, 1), 1) +#test(calc.quo(5, 3), 1) +#test(calc.quo(5, -3), -1) +#test(calc.quo(22.5, 10), 2) +#test(calc.quo(9, 4.5), 2) + +--- calc-quo-divisor-zero-1 --- +// Error: 14-15 divisor must not be zero +#calc.quo(5, 0) + +--- calc-quo-divisor-zero-2 --- +// Error: 16-19 divisor must not be zero +#calc.quo(3.0, 0.0) + +--- calc-min-and-max --- +// Test the `min` and `max` functions. +#test(calc.min(2, -4), -4) +#test(calc.min(3.5, 1e2, -0.1, 3), -0.1) +#test(calc.max(-3, 11), 11) +#test(calc.min("hi"), "hi") + +--- calc-pow-log-exp-ln --- +// Test the `pow`, `log`, `exp`, and `ln` functions. +#test(calc.pow(10, 0), 1) +#test(calc.pow(2, 4), 16) +#test(calc.exp(2), calc.pow(calc.e, 2)) +#test(calc.ln(10), calc.log(10, base: calc.e)) + +--- calc-bit-logical --- +// Test the `bit-not`, `bit-and`, `bit-or` and `bit-xor` functions. +#test(64.bit-not(), -65) +#test(0.bit-not(), -1) +#test((-56).bit-not(), 55) +#test(128.bit-and(192), 128) +#test(192.bit-and(224), 192) +#test((-1).bit-and(325532), 325532) +#test(0.bit-and(-53), 0) +#test(0.bit-or(-1), -1) +#test(5.bit-or(3), 7) +#test((-50).bit-or(3), -49) +#test(64.bit-or(32), 96) +#test((-1).bit-xor(1), -2) +#test(64.bit-xor(96), 32) +#test((-1).bit-xor(-7), 6) +#test(0.bit-xor(492), 492) + +--- calc-bit-shift --- +// Test the `bit-lshift` and `bit-rshift` functions. +#test(32.bit-lshift(2), 128) +#test(694.bit-lshift(0), 694) +#test(128.bit-rshift(2), 32) +#test(128.bit-rshift(12345), 0) +#test((-7).bit-rshift(2), -2) +#test((-7).bit-rshift(12345), -1) +#test(128.bit-rshift(2, logical: true), 32) +#test((-7).bit-rshift(61, logical: true), 7) +#test(128.bit-rshift(12345, logical: true), 0) +#test((-7).bit-rshift(12345, logical: true), 0) + +--- calc-bit-shift-too-large --- +// Error: 2-18 the result is too large +#1.bit-lshift(64) + +--- calc-bit-lshift-negative --- +// Error: 15-17 number must be at least zero +#1.bit-lshift(-1) + +--- calc-bit-rshift-negative --- +// Error: 15-17 number must be at least zero +#1.bit-rshift(-1) + +--- calc-pow-zero-to-power-of-zero --- +// Error: 2-16 zero to the power of zero is undefined +#calc.pow(0, 0) + +--- calc-pow-exponent-too-large --- +// Error: 14-31 exponent is too large +#calc.pow(2, 10000000000000000) + +--- calc-pow-too-large --- +// Error: 2-25 the result is too large +#calc.pow(2, 2147483647) + +--- calc-pow-bad-exponent --- +// Error: 14-36 exponent may not be infinite, subnormal, or NaN +#calc.pow(2, calc.pow(2.0, 10000.0)) + +--- calc-pow-not-real --- +// Error: 2-19 the result is not a real number +#calc.pow(-1, 0.5) + +--- calc-sqrt-not-real --- +// Error: 12-14 cannot take square root of negative number +#calc.sqrt(-1) + +--- calc-root --- +#test(calc.root(12.0, 1), 12.0) +#test(calc.root(9.0, 2), 3.0) +#test(calc.root(27.0, 3), 3.0) +#test(calc.root(-27.0, 3), -3.0) +// 100^(-1/2) = (100^(1/2))^-1 = 1/sqrt(100) +#test(calc.root(100.0, -2), 0.1) + +--- calc-root-zeroth --- +// Error: 17-18 cannot take the 0th root of a number +#calc.root(1.0, 0) + +--- calc-root-negative-even --- +// Error: 24-25 negative numbers do not have a real nth root when n is even +#test(calc.root(-27.0, 4), -3.0) + +--- calc-log-negative --- +// Error: 11-13 value must be strictly positive +#calc.log(-1) + +--- calc-log-bad-base --- +// Error: 20-21 base may not be zero, NaN, infinite, or subnormal +#calc.log(1, base: 0) + +--- calc-log-not-real --- +// Error: 2-24 the result is not a real number +#calc.log(10, base: -1) + +--- calc-fact --- +// Test the `fact` function. +#test(calc.fact(0), 1) +#test(calc.fact(5), 120) + +--- calc-fact-too-large --- +// Error: 2-15 the result is too large +#calc.fact(21) + +--- calc-perm --- +// Test the `perm` function. +#test(calc.perm(0, 0), 1) +#test(calc.perm(5, 3), 60) +#test(calc.perm(5, 5), 120) +#test(calc.perm(5, 6), 0) + +--- calc-perm-too-large --- +// Error: 2-19 the result is too large +#calc.perm(21, 21) + +--- calc-binom --- +// Test the `binom` function. +#test(calc.binom(0, 0), 1) +#test(calc.binom(5, 3), 10) +#test(calc.binom(5, 5), 1) +#test(calc.binom(5, 6), 0) +#test(calc.binom(6, 2), 15) + +--- calc-gcd --- +// Test the `gcd` function. +#test(calc.gcd(112, 77), 7) +#test(calc.gcd(12, 96), 12) +#test(calc.gcd(13, 9), 1) +#test(calc.gcd(13, -9), 1) +#test(calc.gcd(272557, 272557), 272557) +#test(calc.gcd(0, 0), 0) +#test(calc.gcd(7, 0), 7) + +--- calc-lcm --- +// Test the `lcm` function. +#test(calc.lcm(112, 77), 1232) +#test(calc.lcm(12, 96), 96) +#test(calc.lcm(13, 9), 117) +#test(calc.lcm(13, -9), 117) +#test(calc.lcm(272557, 272557), 272557) +#test(calc.lcm(0, 0), 0) +#test(calc.lcm(8, 0), 0) + +--- calc-lcm-too-large --- +// Error: 2-41 the result is too large +#calc.lcm(15486487489457, 4874879896543) + +--- calc-min-nothing --- +// Error: 2-12 expected at least one value +#calc.min() + +--- calc-min-uncomparable --- +// Error: 14-18 cannot compare string and integer +#calc.min(1, "hi") + +--- calc-max-uncomparable --- +// Error: 16-19 cannot compare 1pt with 1em +#calc.max(1em, 1pt) diff --git a/tests/suite/foundations/content.typ b/tests/suite/foundations/content.typ new file mode 100644 index 00000000..afecc124 --- /dev/null +++ b/tests/suite/foundations/content.typ @@ -0,0 +1,120 @@ +--- content-at-default --- +// Test .at() default values for content. +#test(auto, [a].at("doesn't exist", default: auto)) + +--- content-field-syntax --- +// Test fields on elements. +#show list: it => { + test(it.children.len(), 3) +} + +- A +- B +- C + +--- content-field-missing --- +// Error: 25-28 content does not contain field "fun" +#show heading: it => it.fun += A + +--- content-fields --- +// Test content fields method. +#test([a].fields(), (text: "a")) +#test([a *b*].fields(), (children: ([a], [ ], strong[b]))) + +--- content-fields-mutable-invalid --- +#{ + let object = [hi] + // Error: 3-9 cannot mutate fields on content + object.property = "value" +} + +--- content-field-materialized-table --- +// Ensure that fields from set rules are materialized into the element before +// a show rule runs. +#set table(columns: (10pt, auto)) +#show table: it => it.columns +#table[A][B][C][D] + +--- content-field-materialized-heading --- +// Test it again with a different element. +#set heading(numbering: "(I)") +#show heading: set text(size: 11pt, weight: "regular") +#show heading: it => it.numbering += Heading + +--- content-field-materialized-query --- +// Test it with query. +#set raw(lang: "rust") +#context query(<myraw>).first().lang +`raw` <myraw> + +--- content-fields-complex --- +// Integrated test for content fields. +#let compute(equation, ..vars) = { + let vars = vars.named() + let f(elem) = { + let func = elem.func() + if func == text { + let text = elem.text + if regex("^\d+$") in text { + int(text) + } else if text in vars { + int(vars.at(text)) + } else { + panic("unknown math variable: " + text) + } + } else if func == math.attach { + let value = f(elem.base) + if elem.has("t") { + value = calc.pow(value, f(elem.t)) + } + value + } else if elem.has("children") { + elem + .children + .filter(v => v != [ ]) + .split[+] + .map(xs => xs.fold(1, (prod, v) => prod * f(v))) + .fold(0, (sum, v) => sum + v) + } + } + let result = f(equation.body) + [With ] + vars + .pairs() + .map(p => $#p.first() = #p.last()$) + .join(", ", last: " and ") + [ we have:] + $ equation = result $ +} + +#compute($x y + y^2$, x: 2, y: 3) + +--- content-label-has-method --- +// Test whether the label is accessible through the `has` method. +#show heading: it => { + assert(it.has("label")) + it +} + += Hello, world! <my-label> + +--- content-label-field-access --- +// Test whether the label is accessible through field syntax. +#show heading: it => { + assert(str(it.label) == "my-label") + it +} + += Hello, world! <my-label> + +--- content-label-fields-method --- +// Test whether the label is accessible through the fields method. +#show heading: it => { + assert("label" in it.fields()) + assert(str(it.fields().label) == "my-label") + it +} + += Hello, world! <my-label> diff --git a/tests/suite/foundations/context.typ b/tests/suite/foundations/context.typ new file mode 100644 index 00000000..fea9f544 --- /dev/null +++ b/tests/suite/foundations/context.typ @@ -0,0 +1,65 @@ +// Test context expressions. + +--- context-body-atomic-in-markup --- +// Test that context body is parsed as atomic expression. +#let c = [#context "hello".] +#test(c.children.first().func(), (context none).func()) +#test(c.children.last(), [.]) + +--- context-element-constructor-forbidden --- +// Test that manual construction is forbidden. +// Error: 2-25 cannot be constructed manually +#(context none).func()() + +--- context-in-show-rule --- +// Test that show rule establishes context. +#set heading(numbering: "1.") +#show heading: it => test( + counter(heading).get(), + (intro: (1,), back: (2,)).at(str(it.label)), +) + += Introduction <intro> += Background <back> + +--- context-in-show-rule-query --- +// Test that show rule on non-locatable element allows `query`. +// Error: 18-47 Assertion failed: 2 != 3 +#show emph: _ => test(query(heading).len(), 3) +#show strong: _ => test(query(heading).len(), 2) += Introduction += Background +*Hi* _there_ + +--- context-assign-to-captured-variable --- +// Test error when captured variable is assigned to. +#let i = 0 +// Error: 11-12 variables from outside the context expression are read-only and cannot be modified +#context (i = 1) + +--- context-compatibility-locate --- +#let s = state("x", 0) +#let compute(expr) = [ + #s.update(x => + eval(expr.replace("x", str(x))) + ) + New value is #s.display(). +] + +#locate(loc => { + let elem = query(<here>, loc).first() + test(s.at(elem.location()), 13) +}) + +#compute("10") \ +#compute("x + 3") \ +*Here.* <here> \ +#compute("x * 2") \ +#compute("x - 5") + +--- context-compatibility-styling --- +#style(styles => measure([it], styles).width < 20pt) + +--- context-compatibility-counter-display --- +#counter(heading).update(10) +#counter(heading).display(n => test(n, 10)) diff --git a/tests/suite/foundations/datetime.typ b/tests/suite/foundations/datetime.typ new file mode 100644 index 00000000..b54c11f3 --- /dev/null +++ b/tests/suite/foundations/datetime.typ @@ -0,0 +1,93 @@ +--- datetime-constructor-empty --- +// Error: 2-12 at least one of date or time must be fully specified +#datetime() + +--- datetime-constructor-time-invalid --- +// Error: 2-42 time is invalid +#datetime(hour: 25, minute: 0, second: 0) + +--- datetime-constructor-date-invalid --- +// Error: 2-41 date is invalid +#datetime(year: 2000, month: 2, day: 30) + +--- datetime-display --- +// Test displaying of dates. +#test(datetime(year: 2023, month: 4, day: 29).display(), "2023-04-29") +#test(datetime(year: 2023, month: 4, day: 29).display("[year]"), "2023") +#test( + datetime(year: 2023, month: 4, day: 29) + .display("[year repr:last_two]"), + "23", +) +#test( + datetime(year: 2023, month: 4, day: 29) + .display("[year] [month repr:long] [day] [week_number] [weekday]"), + "2023 April 29 17 Saturday", +) + +// Test displaying of times +#test(datetime(hour: 14, minute: 26, second: 50).display(), "14:26:50") +#test(datetime(hour: 14, minute: 26, second: 50).display("[hour]"), "14") +#test( + datetime(hour: 14, minute: 26, second: 50) + .display("[hour repr:12 padding:none]"), + "2", +) +#test( + datetime(hour: 14, minute: 26, second: 50) + .display("[hour], [minute], [second]"), "14, 26, 50", +) + +// Test displaying of datetimes +#test( + datetime(year: 2023, month: 4, day: 29, hour: 14, minute: 26, second: 50).display(), + "2023-04-29 14:26:50", +) + +// Test getting the year/month/day etc. of a datetime +#let d = datetime(year: 2023, month: 4, day: 29, hour: 14, minute: 26, second: 50) +#test(d.year(), 2023) +#test(d.month(), 4) +#test(d.weekday(), 6) +#test(d.day(), 29) +#test(d.hour(), 14) +#test(d.minute(), 26) +#test(d.second(), 50) + +#let e = datetime(year: 2023, month: 4, day: 29) +#test(e.hour(), none) +#test(e.minute(), none) +#test(e.second(), none) + +// Test today +#test(datetime.today().display(), "1970-01-01") +#test(datetime.today(offset: auto).display(), "1970-01-01") +#test(datetime.today(offset: 2).display(), "1970-01-01") + +--- datetime-ordinal --- +// Test date methods. +#test(datetime(day: 1, month: 1, year: 2000).ordinal(), 1); +#test(datetime(day: 1, month: 3, year: 2000).ordinal(), 31 + 29 + 1); +#test(datetime(day: 31, month: 12, year: 2000).ordinal(), 366); +#test(datetime(day: 1, month: 3, year: 2001).ordinal(), 31 + 28 + 1); +#test(datetime(day: 31, month: 12, year: 2001).ordinal(), 365); + +--- datetime-display-missing-closing-bracket --- +// Error: 27-34 missing closing bracket for bracket at index 0 +#datetime.today().display("[year") + +--- datetime-display-invalid-component --- +// Error: 27-38 invalid component name 'nothing' at index 1 +#datetime.today().display("[nothing]") + +--- datetime-display-invalid-modifier --- +// Error: 27-50 invalid modifier 'wrong' at index 6 +#datetime.today().display("[year wrong:last_two]") + +--- datetime-display-expected-component --- +// Error: 27-33 expected component name at index 2 +#datetime.today().display(" []") + +--- datetime-display-insufficient-information --- +// Error: 2-36 failed to format datetime (insufficient information) +#datetime.today().display("[hour]") diff --git a/tests/suite/foundations/dict.typ b/tests/suite/foundations/dict.typ new file mode 100644 index 00000000..2c2d2a41 --- /dev/null +++ b/tests/suite/foundations/dict.typ @@ -0,0 +1,266 @@ +// Test dictionaries. + +--- dict-basic-syntax --- + +// Empty +#(:) + +// Two pairs and string key. +#let dict = (normal: 1, "spacy key": 2) +#dict + +#test(dict.normal, 1) +#test(dict.at("spacy key"), 2) + +--- dict-fields --- +// Test field on dictionary. +#let dict = (nothing: "ness", hello: "world") +#test(dict.nothing, "ness") +#{ + let world = dict + .hello + + test(world, "world") +} + +--- dict-missing-field --- +// Error: 6-13 dictionary does not contain key "invalid" +#(:).invalid + +--- dict-bad-key --- +// Error: 3-7 expected string, found boolean +// Error: 16-18 expected string, found integer +#(true: false, 42: 3) + +--- dict-duplicate-key --- +// Error: 24-29 duplicate key: first +#(first: 1, second: 2, first: 3) + +--- dict-duplicate-key-stringy --- +// Error: 17-20 duplicate key: a +#(a: 1, "b": 2, "a": 3) + +--- dict-bad-expression --- +// Simple expression after already being identified as a dictionary. +// Error: 9-10 expected named or keyed pair, found identifier +#(a: 1, b) + +--- dict-leading-colon --- +// Identified as dictionary due to initial colon. +// The boolean key is allowed for now since it will only cause an error at the evaluation stage. +// Error: 4-5 expected named or keyed pair, found integer +// Error: 17 expected expression +#(:1 b:"", true:) + +--- spread-into-dict --- +#{ + let x = (a: 1) + let y = (b: 2) + let z = (a: 3) + test((:..x, ..y, ..z), (a: 3, b: 2)) + test((..(a: 1), b: 2), (a: 1, b: 2)) +} + +--- spread-array-into-dict --- +// Error: 3-11 cannot spread array into dictionary +#(..(1, 2), a: 1) + +--- dict-at-lvalue --- +// Test lvalue and rvalue access. +#{ + let dict = (a: 1, "b b": 1) + dict.at("b b") += 1 + dict.state = (ok: true, err: false) + test(dict, (a: 1, "b b": 2, state: (ok: true, err: false))) + test(dict.state.ok, true) + dict.at("state").ok = false + test(dict.state.ok, false) + test(dict.state.err, false) +} + +--- dict-at-missing-key --- +// Test rvalue missing key. +#{ + let dict = (a: 1, b: 2) + // Error: 11-23 dictionary does not contain key "c" and no default value was specified + let x = dict.at("c") +} + +--- dict-at-default --- +// Test default value. +#test((a: 1, b: 2).at("b", default: 3), 2) +#test((a: 1, b: 2).at("c", default: 3), 3) + +--- dict-insert --- +// Test insert. +#{ + let dict = (a: 1, b: 2) + dict.insert("b", 3) + test(dict, (a: 1, b: 3)) + dict.insert("c", 5) + test(dict, (a: 1, b: 3, c: 5)) +} + +--- dict-remove-with-default --- +// Test remove with default value. +#{ + let dict = (a: 1, b: 2) + test(dict.remove("b", default: 3), 2) +} + +#{ + let dict = (a: 1, b: 2) + test(dict.remove("c", default: 3), 3) +} + +--- dict-missing-lvalue --- +// Missing lvalue is not automatically none-initialized. +#{ + let dict = (:) + // Error: 3-9 dictionary does not contain key "b" + // Hint: 3-9 use `insert` to add or update values + dict.b += 1 +} + +--- dict-basic-methods --- +// Test dictionary methods. +#let dict = (a: 3, c: 2, b: 1) +#test("c" in dict, true) +#test(dict.len(), 3) +#test(dict.values(), (3, 2, 1)) +#test(dict.pairs().map(p => p.first() + str(p.last())).join(), "a3c2b1") + +#dict.remove("c") +#test("c" in dict, false) +#test(dict, (a: 3, b: 1)) + +--- dict-from-module --- +// Test dictionary constructor +#dictionary(sys).at("version") +#dictionary(sys).at("no-crash", default: none) + +--- dict-remove-order --- +// Test that removal keeps order. +#let dict = (a: 1, b: 2, c: 3, d: 4) +#dict.remove("b") +#test(dict.keys(), ("a", "c", "d")) + +--- dict-temporary-lvalue --- +// Error: 3-15 cannot mutate a temporary value +#((key: "val").other = "some") + +--- dict-function-item-not-a-method --- +#{ + let dict = ( + call-me: () => 1, + ) + // Error: 8-15 type dictionary has no method `call-me` + // Hint: 8-15 to call the function stored in the dictionary, surround the field access with parentheses, e.g. `(dict.call-me)(..)` + dict.call-me() +} + +--- dict-item-missing-method --- +#{ + let dict = ( + nonfunc: 1 + ) + + // Error: 8-15 type dictionary has no method `nonfunc` + // Hint: 8-15 did you mean to access the field `nonfunc`? + dict.nonfunc() +} + +--- dict-dynamic-uplicate-key --- +#let a = "hello" +#let b = "world" +#let c = "value" +#let d = "conflict" + +#assert.eq(((a): b), ("hello": "world")) +#assert.eq(((a): 1, (a): 2), ("hello": 2)) +#assert.eq((hello: 1, (a): 2), ("hello": 2)) +#assert.eq((a + b: c, (a + b): d, (a): "value2", a: "value3"), ("helloworld": "conflict", "hello": "value2", "a": "value3")) + +--- issue-1338-dictionary-underscore --- +#let foo = "foo" +#let bar = "bar" +// Error: 8-9 expected expression, found underscore +// Error: 16-17 expected expression, found underscore +#(foo: _, bar: _) + +--- issue-1342-dictionary-bare-expressions --- +// Error: 5-8 expected named or keyed pair, found identifier +// Error: 10-13 expected named or keyed pair, found identifier +#(: foo, bar) + +--- issue-3154-dict-at-not-contained --- +#{ + let dict = (a: 1) + // Error: 3-15 dictionary does not contain key "b" and no default value was specified + dict.at("b") +} + +--- issue-3154-dict-at-missing-default --- +#{ + let dict = (a: 1) + test(dict.at("b", default: 0), 0) +} + +--- issue-3154-dict-at-missing-mutable --- +#{ + let dict = (a: 1) + // Error: 3-15 dictionary does not contain key "b" + // Hint: 3-15 use `insert` to add or update values + dict.at("b") = 9 +} + +--- issue-3154-dict-at-missing-mutable-default --- +#{ + let dict = (a: 1) + // Error: 3-27 dictionary does not contain key "b" + // Hint: 3-27 use `insert` to add or update values + dict.at("b", default: 0) = 9 +} + +--- issue-3154-dict-syntax-missing --- +#{ + let dict = (a: 1) + // Error: 8-9 dictionary does not contain key "b" + dict.b +} + +--- issue-3154-dict-syntax-missing-mutable --- +#{ + let dict = (a: 1) + dict.b = 9 + test(dict, (a: 1, b: 9)) +} + +--- issue-3154-dict-syntax-missing-add-assign --- +#{ + let dict = (a: 1) + // Error: 3-9 dictionary does not contain key "b" + // Hint: 3-9 use `insert` to add or update values + dict.b += 9 +} + +--- issue-3232-dict-unexpected-keys-sides --- +// Confusing "expected relative length or dictionary, found dictionary" +// Error: 16-58 unexpected keys "unexpected" and "unexpected-too" +#block(outset: (unexpected: 0.5em, unexpected-too: 0.2em), [Hi]) + +--- issue-3232-dict-unexpected-keys-corners --- +// Error: 14-56 unexpected keys "unexpected" and "unexpected-too" +#box(radius: (unexpected: 0.5em, unexpected-too: 0.5em), [Hi]) + +--- issue-3232-dict-unexpected-key-sides --- +// Error: 16-49 unexpected key "unexpected", valid keys are "left", "top", "right", "bottom", "x", "y", and "rest" +#block(outset: (unexpected: 0.2em, right: 0.5em), [Hi]) // The 1st key is unexpected + +--- issue-3232-dict-unexpected-key-corners --- +// Error: 14-50 unexpected key "unexpected", valid keys are "top-left", "top-right", "bottom-right", "bottom-left", "left", "top", "right", "bottom", and "rest" +#box(radius: (top-left: 0.5em, unexpected: 0.5em), [Hi]) // The 2nd key is unexpected + +--- issue-3232-dict-empty --- +#block(outset: (:), [Hi]) // Ok +#box(radius: (:), [Hi]) // Ok diff --git a/tests/suite/foundations/duration.typ b/tests/suite/foundations/duration.typ new file mode 100644 index 00000000..7e53f703 --- /dev/null +++ b/tests/suite/foundations/duration.typ @@ -0,0 +1,103 @@ +// Test durations. + +--- duration-negate --- +// Test negating durations. +#test(-duration(hours: 2), duration(hours: -2)) + +--- duration-add-and-subtract --- +// Test adding and subtracting durations. +#test(duration(weeks: 1, hours: 1), duration(weeks: 1) + duration(hours: 1)) +#test(duration(weeks: 1, hours: -1), duration(weeks: 1) - duration(hours: 1)) +#test(duration(days: 6, hours: 23), duration(weeks: 1) - duration(hours: 1)) + +--- duration-add-and-subtract-dates --- +// Test adding and subtracting durations and dates. +#let d = datetime(day: 1, month: 1, year: 2000) +#let d2 = datetime(day: 1, month: 2, year: 2000) +#test(d + duration(weeks: 2), datetime(day: 15, month: 1, year: 2000)) +#test(d + duration(days: 3), datetime(day: 4, month: 1, year: 2000)) +#test(d + duration(weeks: 1, days: 3), datetime(day: 11, month: 1, year: 2000)) +#test(d2 + duration(days: -1), datetime(day: 31, month: 1, year: 2000)) +#test(d2 + duration(days: -3), datetime(day: 29, month: 1, year: 2000)) +#test(d2 + duration(weeks: -1), datetime(day: 25, month: 1, year: 2000)) +#test(d + duration(days: -1), datetime(day: 31, month: 12, year: 1999)) +#test(d + duration(weeks: 1, days: -7), datetime(day: 1, month: 1, year: 2000)) +#test(d2 - duration(days: 1), datetime(day: 31, month: 1, year: 2000)) +#test(d2 - duration(days: 3), datetime(day: 29, month: 1, year: 2000)) +#test(d2 - duration(weeks: 1), datetime(day: 25, month: 1, year: 2000)) +#test(d - duration(days: 1), datetime(day: 31, month: 12, year: 1999)) +#test(datetime(day: 31, month: 1, year: 2000) + duration(days: 1), d2) +#test( + datetime(day: 31, month: 12, year: 2000) + duration(days: 1), + datetime(day: 1, month: 1, year: 2001), +) + +--- duration-add-and-subtract-times --- +// Test adding and subtracting durations and times. +#let a = datetime(hour: 12, minute: 0, second: 0) +#test(a + duration(hours: 1, minutes: -60), datetime(hour: 12, minute: 0, second: 0)) +#test(a + duration(hours: 2), datetime(hour: 14, minute: 0, second: 0)) +#test(a + duration(minutes: 10), datetime(hour: 12, minute: 10, second: 0)) +#test(a + duration(seconds: 30), datetime(hour: 12, minute: 0, second: 30)) +#test(a + duration(hours: -2), datetime(hour: 10, minute: 0, second: 0)) +#test(a - duration(hours: 2), datetime(hour: 10, minute: 0, second: 0)) +#test(a + duration(minutes: -10), datetime(hour: 11, minute: 50, second: 0)) +#test(a - duration(minutes: 10), datetime(hour: 11, minute: 50, second: 0)) +#test(a + duration(seconds: -30), datetime(hour: 11, minute: 59, second: 30)) +#test(a - duration(seconds: 30), datetime(hour: 11, minute: 59, second: 30)) +#test( + a + duration(hours: 1, minutes: 13, seconds: 13), + datetime(hour: 13, minute: 13, second: 13), +) + +--- duration-add-and-subtract-datetimes --- +// Test adding and subtracting durations and datetimes. +#test( + datetime(day: 1, month: 1, year: 2000, hour: 12, minute: 0, second: 0) + + duration(weeks: 1, days: 3, hours: -13, minutes: 10, seconds: -10 ), + datetime(day: 10, month: 1, year: 2000, hour: 23, minute: 9, second: 50), +) +#test( + datetime(day: 1, month: 1, year: 2000, hour: 12, minute: 0, second: 0) + + duration(weeks: 1, days: 3, minutes: 10) + - duration(hours: 13, seconds: 10), + datetime(day: 10, month: 1, year: 2000, hour: 23, minute: 9, second: 50), +) + +--- duration-from-date-subtraction --- +// Test subtracting dates. +#let a = datetime(hour: 12, minute: 0, second: 0) +#let b = datetime(day: 1, month: 1, year: 2000) +#test(datetime(hour: 14, minute: 0, second: 0) - a, duration(hours: 2)) +#test(datetime(hour: 14, minute: 0, second: 0) - a, duration(minutes: 120)) +#test(datetime(hour: 13, minute: 0, second: 0) - a, duration(seconds: 3600)) +#test(datetime(day: 1, month: 2, year: 2000) - b, duration(days: 31)) +#test(datetime(day: 15, month: 1, year: 2000) - b, duration(weeks: 2)) + +--- duration-multiply-with-number --- +// Test multiplying and dividing durations with numbers. +#test(duration(minutes: 10) * 6, duration(hours: 1)) +#test(duration(minutes: 10) * 2, duration(minutes: 20)) +#test(duration(minutes: 10) * 2.5, duration(minutes: 25)) +#test(duration(minutes: 10) / 2, duration(minutes: 5)) +#test(duration(minutes: 10) / 2.5, duration(minutes: 4)) + +--- duration-divide --- +// Test dividing durations with durations +#test(duration(minutes: 20) / duration(hours: 1), 1 / 3) +#test(duration(minutes: 20) / duration(minutes: 10), 2) +#test(duration(minutes: 20) / duration(minutes: 8), 2.5) + +--- duration-compare --- +// Test comparing durations +#test(duration(minutes: 20) > duration(minutes: 10), true) +#test(duration(minutes: 20) >= duration(minutes: 10), true) +#test(duration(minutes: 10) < duration(minutes: 20), true) +#test(duration(minutes: 10) <= duration(minutes: 20), true) +#test(duration(minutes: 10) == duration(minutes: 10), true) +#test(duration(minutes: 10) != duration(minutes: 20), true) +#test(duration(minutes: 10) <= duration(minutes: 10), true) +#test(duration(minutes: 10) >= duration(minutes: 10), true) +#test(duration(minutes: 20) < duration(minutes: 10), false) +#test(duration(minutes: 20) <= duration(minutes: 10), false) +#test(duration(minutes: 20) == duration(minutes: 10), false) diff --git a/tests/suite/foundations/eval.typ b/tests/suite/foundations/eval.typ new file mode 100644 index 00000000..f85146b2 --- /dev/null +++ b/tests/suite/foundations/eval.typ @@ -0,0 +1,54 @@ +--- eval --- +// Test the eval function. +#test(eval("1 + 2"), 3) +#test(eval("1 + x", scope: (x: 3)), 4) +#test(eval("let x = x + 1; x + 1", scope: (x: 1)), 3) + +--- eval-mode --- +// Test evaluation in other modes. +#eval("[_Hello" + " World!_]") \ +#eval("_Hello" + " World!_", mode: "markup") \ +#eval("RR_1^NN", mode: "math", scope: (RR: math.NN, NN: math.RR)) + +--- eval-syntax-error-1 --- +// Error: 7-12 expected pattern +#eval("let") + +--- eval-in-show-rule --- +#show raw: it => text(font: "PT Sans", eval("[" + it.text + "]")) + +Interacting +``` +#set text(blue) +Blue #move(dy: -0.15em)[🌊] +``` + +--- eval-runtime-error --- +// Error: 7-17 cannot continue outside of loop +#eval("continue") + +--- eval-syntax-error-2 --- +// Error: 7-12 expected semicolon or line break +#eval("1 2") + +--- eval-path-resolve --- +// Test absolute path. +#eval("image(\"/assets/images/tiger.jpg\", width: 50%)") + +--- eval-path-resolve-in-show-rule --- +#show raw: it => eval(it.text, mode: "markup") + +``` +#show emph: image("/assets/images/tiger.jpg", width: 50%) +_Tiger!_ +``` + +--- eval-path-resolve-relative --- +// Test relative path. +#test(eval(`"HELLO" in read("./eval.typ")`.text), true) + +--- issue-2055-math-eval --- +// Evaluating a math expr should renders the same as an equation +#eval(mode: "math", "f(a) = cases(a + b\, space space x >= 3,a + b\, space space x = 5)") + +$f(a) = cases(a + b\, space space x >= 3,a + b\, space space x = 5)$ diff --git a/tests/suite/foundations/float.typ b/tests/suite/foundations/float.typ new file mode 100644 index 00000000..770533b9 --- /dev/null +++ b/tests/suite/foundations/float.typ @@ -0,0 +1,66 @@ +--- float-constructor --- +#test(float(10), 10.0) +#test(float(50% * 30%), 0.15) +#test(float("31.4e-1"), 3.14) +#test(float("31.4e\u{2212}1"), 3.14) +#test(float("3.1415"), 3.1415) +#test(float("-7654.321"), -7654.321) +#test(float("\u{2212}7654.321"), -7654.321) +#test(type(float(10)), float) + +--- float-constructor-bad-type --- +// Error: 8-13 expected float, boolean, integer, ratio, or string, found type +#float(float) + +--- float-constructor-bad-value --- +// Error: 8-15 invalid float: 1.2.3 +#float("1.2.3") + +--- float-is-nan --- +// Test float `is-nan()`. +#test(float(calc.nan).is-nan(), true) +#test(float(10).is-nan(), false) + +--- float-is-infinite --- +// Test float `is-infinite()`. +#test(float(calc.inf).is-infinite(), true) +#test(float(-calc.inf).is-infinite(), true) +#test(float(10).is-infinite(), false) +#test(float(-10).is-infinite(), false) + +--- float-signum --- +// Test float `signum()` +#test(float(0.0).signum(), 1.0) +#test(float(1.0).signum(), 1.0) +#test(float(-1.0).signum(), -1.0) +#test(float(10.0).signum(), 1.0) +#test(float(-10.0).signum(), -1.0) +#test(float(calc.nan).signum().is-nan(), true) + +--- float-repr --- +// Test the `repr` function with floats. +#repr(12.0) \ +#repr(3.14) \ +#repr(1234567890.0) \ +#repr(0123456789.0) \ +#repr(0.0) \ +#repr(-0.0) \ +#repr(-1.0) \ +#repr(-9876543210.0) \ +#repr(-0987654321.0) \ +#repr(-3.14) \ +#repr(4.0 - 8.0) + +--- float-display --- +// Test floats. +#12.0 \ +#3.14 \ +#1234567890.0 \ +#0123456789.0 \ +#0.0 \ +#(-0.0) \ +#(-1.0) \ +#(-9876543210.0) \ +#(-0987654321.0) \ +#(-3.14) \ +#(4.0 - 8.0) diff --git a/tests/suite/foundations/int.typ b/tests/suite/foundations/int.typ new file mode 100644 index 00000000..0c85dcab --- /dev/null +++ b/tests/suite/foundations/int.typ @@ -0,0 +1,73 @@ +--- int-base-alternative --- +// Test numbers with alternative bases. +#test(0x10, 16) +#test(0b1101, 13) +#test(0xA + 0xa, 0x14) + +--- int-base-binary-invalid --- +// Error: 2-7 invalid binary number: 0b123 +#0b123 + +--- int-base-hex-invalid --- +// Error: 2-8 invalid hexadecimal number: 0x123z +#0x123z + +--- int-constructor --- +// Test conversion to numbers. +#test(int(false), 0) +#test(int(true), 1) +#test(int(10), 10) +#test(int("150"), 150) +#test(int("-834"), -834) +#test(int("\u{2212}79"), -79) +#test(int(10 / 3), 3) + +--- int-constructor-bad-type --- +// Error: 6-10 expected integer, boolean, float, or string, found length +#int(10pt) + +--- int-constructor-bad-value --- +// Error: 6-12 invalid integer: nope +#int("nope") + +--- int-signum --- +// Test int `signum()` +#test(int(0).signum(), 0) +#test(int(1.0).signum(), 1) +#test(int(-1.0).signum(), -1) +#test(int(10.0).signum(), 1) +#test(int(-10.0).signum(), -1) + +--- int-repr --- +// Test the `repr` function with integers. +#repr(12) \ +#repr(1234567890) \ +#repr(0123456789) \ +#repr(0) \ +#repr(-0) \ +#repr(-1) \ +#repr(-9876543210) \ +#repr(-0987654321) \ +#repr(4 - 8) + +--- int-display --- +// Test integers. +#12 \ +#1234567890 \ +#0123456789 \ +#0 \ +#(-0) \ +#(-1) \ +#(-9876543210) \ +#(-0987654321) \ +#(4 - 8) + +--- issue-int-constructor --- +// Test that integer -> integer conversion doesn't do a roundtrip through float. +#let x = 9223372036854775800 +#test(type(x), int) +#test(int(x), x) + +--- number-invalid-suffix --- +// Error: 2-4 invalid number suffix: u +#1u diff --git a/tests/suite/foundations/label.typ b/tests/suite/foundations/label.typ new file mode 100644 index 00000000..2cde102c --- /dev/null +++ b/tests/suite/foundations/label.typ @@ -0,0 +1,70 @@ +// Test labels. + +--- label-show-where-selector --- +// Test labelled headings. +#show heading: set text(10pt) +#show heading.where(label: <intro>): underline + += Introduction <intro> +The beginning. + += Conclusion +The end. + +--- label-after-expression --- +// Test label after expression. +#show strong.where(label: <v>): set text(red) + +#let a = [*A*] +#let b = [*B*] +#a <v> #b + +--- label-on-text --- +// Test labelled text. +#show "t": it => { + set text(blue) if it.has("label") and it.label == <last> + it +} + +This is a thing #[that <last>] happened. + +--- label-dynamic-show-set --- +// Test abusing dynamic labels for styling. +#show <red>: set text(red) +#show <blue>: set text(blue) + +*A* *B* <red> *C* #label("bl" + "ue") *D* + +--- label-after-parbreak --- +// Test that label ignores parbreak. +#show <hide>: none + +_Hidden_ +<hide> + +_Hidden_ + +<hide> +_Visible_ + +--- label-in-block --- +// Test that label only works within one content block. +#show <strike>: strike +*This is* #[<strike>] *protected.* +*This is not.* <strike> + +--- label-unclosed-is-text --- +// Test that incomplete label is text. +1 < 2 is #if 1 < 2 [not] a label. + +--- label-text-styled-and-sequence --- +// Test label on text, styled, and sequence. +#test([Hello<hi>].label, <hi>) +#test([#[A *B* C]<hi>].label, <hi>) +#test([#text(red)[Hello]<hi>].label, <hi>) + +--- label-string-conversion --- +// Test getting the name of a label. +#test(str(<hey>), "hey") +#test(str(label("hey")), "hey") +#test(str([Hmm<hey>].label), "hey") diff --git a/tests/suite/foundations/panic.typ b/tests/suite/foundations/panic.typ new file mode 100644 index 00000000..5d9d4046 --- /dev/null +++ b/tests/suite/foundations/panic.typ @@ -0,0 +1,14 @@ +--- panic --- +// Test panic. +// Error: 2-9 panicked +#panic() + +--- panic-with-int --- +// Test panic. +// Error: 2-12 panicked with: 123 +#panic(123) + +--- panic-with-str --- +// Test panic. +// Error: 2-24 panicked with: "this is wrong" +#panic("this is wrong") diff --git a/tests/suite/foundations/plugin.typ b/tests/suite/foundations/plugin.typ new file mode 100644 index 00000000..0842980e --- /dev/null +++ b/tests/suite/foundations/plugin.typ @@ -0,0 +1,47 @@ +// Test WebAssembly plugins. + +--- plugin-basic --- +#let p = plugin("/assets/plugins/hello.wasm") +#test(p.hello(), bytes("Hello from wasm!!!")) +#test(p.double_it(bytes("hey!")), bytes("hey!.hey!")) +#test( + p.shuffle(bytes("value1"), bytes("value2"), bytes("value3")), + bytes("value3-value1-value2"), +) + +--- plugin-wrong-number-of-arguments --- +#let p = plugin("/assets/plugins/hello.wasm") + +// Error: 2-20 plugin function takes 0 arguments, but 1 was given +#p.hello(bytes("")) + +--- plugin-wrong-argument-type --- +#let p = plugin("/assets/plugins/hello.wasm") + +// Error: 10-14 expected bytes, found boolean +// Error: 27-29 expected bytes, found integer +#p.hello(true, bytes(()), 10) + +--- plugin-error --- +#let p = plugin("/assets/plugins/hello.wasm") + +// Error: 2-17 plugin errored with: This is an `Err` +#p.returns_err() + +--- plugin-panic --- +#let p = plugin("/assets/plugins/hello.wasm") + +// Error: 2-16 plugin panicked: wasm `unreachable` instruction executed +#p.will_panic() + +--- plugin-out-of-bounds-read --- +#let p = plugin("/assets/plugins/plugin-oob.wasm") + +// Error: 2-14 plugin tried to read out of bounds: pointer 0x40000000 is out of bounds for read of length 1 +#p.read_oob() + +--- plugin-out-of-bounds-write --- +#let p = plugin("/assets/plugins/plugin-oob.wasm") + +// Error: 2-27 plugin tried to write out of bounds: pointer 0x40000000 is out of bounds for write of length 3 +#p.write_oob(bytes("xyz")) diff --git a/tests/suite/foundations/repr.typ b/tests/suite/foundations/repr.typ new file mode 100644 index 00000000..f9346faa --- /dev/null +++ b/tests/suite/foundations/repr.typ @@ -0,0 +1,51 @@ +--- repr --- +#test(repr(ltr), "ltr") +#test(repr((1, 2, false, )), "(1, 2, false)") + +--- repr-literals --- +// Literal values. +#auto \ +#none (empty) \ +#true \ +#false + +--- repr-numerical --- +// Numerical values. +#1 \ +#1.0e-4 \ +#3.15 \ +#1e-10 \ +#50.368% \ +#0.0000012345pt \ +#4.5cm \ +#12e1pt \ +#2.5rad \ +#45deg \ +#1.7em \ +#(1cm + 0em) \ +#(2em + 10pt) \ +#2.3fr + +--- repr-misc --- +// Colors and strokes. +#set text(0.8em) +#rgb("f7a205") \ +#(2pt + rgb("f7a205")) + +// Strings and escaping. +#raw(repr("hi"), lang: "typc") +#repr("a\n[]\"\u{1F680}string") + +// Content. +#raw(lang: "typc", repr[*Hey*]) + +// Functions. +#let f(x) = x +#f \ +#rect \ +#(() => none) + +// Types. +#int \ +#type("hi") \ +#type((a: 1)) diff --git a/tests/suite/foundations/str.typ b/tests/suite/foundations/str.typ new file mode 100644 index 00000000..025ec53d --- /dev/null +++ b/tests/suite/foundations/str.typ @@ -0,0 +1,315 @@ +// Test the string methods. + +--- str-constructor --- +// Test conversion to string. +#test(str(123), "123") +#test(str(123, base: 3), "11120") +#test(str(-123, base: 16), "−7b") +#test(str(9223372036854775807, base: 36), "1y2p0ij32e8e7") +#test(str(50.14), "50.14") +#test(str(10 / 3).len() > 10, true) + +--- str-from-float --- +// Test the `str` function with floats. +#test(str(12.0), "12") +#test(str(3.14), "3.14") +#test(str(1234567890.0), "1234567890") +#test(str(0123456789.0), "123456789") +#test(str(0.0), "0") +#test(str(-0.0), "0") +#test(str(-1.0), "−1") +#test(str(-9876543210.0), "−9876543210") +#test(str(-0987654321.0), "−987654321") +#test(str(-3.14), "−3.14") +#test(str(4.0 - 8.0), "−4") + +--- str-from-int --- +// Test the `str` function with integers. +#test(str(12), "12") +#test(str(1234567890), "1234567890") +#test(str(0123456789), "123456789") +#test(str(0), "0") +#test(str(-0), "0") +#test(str(-1), "−1") +#test(str(-9876543210), "−9876543210") +#test(str(-0987654321), "−987654321") +#test(str(4 - 8), "−4") + +--- str-constructor-bad-type --- +// Error: 6-8 expected integer, float, version, bytes, label, type, or string, found content +#str([]) + +--- str-constructor-bad-base --- +// Error: 17-19 base must be between 2 and 36 +#str(123, base: 99) + +--- str-constructor-unsupported-base --- +// Error: 18-19 base is only supported for integers +#str(1.23, base: 2) + +--- str-from-and-to-unicode --- +// Test the unicode function. +#test(str.from-unicode(97), "a") +#test(str.to-unicode("a"), 97) + +--- str-from-unicode-bad-type --- +// Error: 19-22 expected integer, found content +#str.from-unicode([a]) + +--- str-to-unicode-bad-type --- +// Error: 17-21 expected exactly one character +#str.to-unicode("ab") + +--- str-from-unicode-negative --- +// Error: 19-21 number must be at least zero +#str.from-unicode(-1) + +--- str-from-unicode-bad-value --- +// Error: 2-28 0x110000 is not a valid codepoint +#str.from-unicode(0x110000) // 0x10ffff is the highest valid code point + +--- string-len --- +// Test the `len` method. +#test("Hello World!".len(), 12) + +--- string-first-and-last --- +// Test the `first` and `last` methods. +#test("Hello".first(), "H") +#test("Hello".last(), "o") +#test("🏳️🌈A🏳️⚧️".first(), "🏳️🌈") +#test("🏳️🌈A🏳️⚧️".last(), "🏳️⚧️") + +--- string-first-empty --- +// Error: 2-12 string is empty +#"".first() + +--- string-last-empty --- +// Error: 2-11 string is empty +#"".last() + +--- string-at --- +// Test the `at` method. +#test("Hello".at(1), "e") +#test("Hello".at(4), "o") +#test("Hello".at(-1), "o") +#test("Hello".at(-2), "l") +#test("Hey: 🏳️🌈 there!".at(5), "🏳️🌈") + +--- string-at-default --- +// Test `at`'s 'default' parameter. +#test("z", "Hello".at(5, default: "z")) + +--- string-at-not-a-char-boundary --- +// Error: 2-14 string index 2 is not a character boundary +#"🏳️🌈".at(2) + +--- string-at-out-of-bounds --- +// Error: 2-15 no default value was specified and string index out of bounds (index: 5, len: 5) +#"Hello".at(5) + +--- string-at-at-default-other-type --- +#test("Hello".at(5, default: (a: 10)), (a: 10)) + +--- string-slice --- +// Test the `slice` method. +#test("abc".slice(1, 2), "b") +#test("abc🏡def".slice(2, 7), "c🏡") +#test("abc🏡def".slice(2, -2), "c🏡d") +#test("abc🏡def".slice(-3, -1), "de") + +--- string-slice-not-a-char-boundary --- +// Error: 2-21 string index -1 is not a character boundary +#"🏳️🌈".slice(0, -1) + +--- string-clusters --- +// Test the `clusters` and `codepoints` methods. +#test("abc".clusters(), ("a", "b", "c")) +#test("abc".clusters(), ("a", "b", "c")) +#test("🏳️🌈!".clusters(), ("🏳️🌈", "!")) + +--- string-codepoints --- +#test("🏳️🌈!".codepoints(), ("🏳", "\u{fe0f}", "\u{200d}", "🌈", "!")) + +--- string-contains --- +// Test the `contains` method. +#test("abc".contains("b"), true) +#test("b" in "abc", true) +#test("1234f".contains(regex("\d")), true) +#test(regex("\d") in "1234f", true) +#test("abc".contains("d"), false) +#test("1234g" in "1234f", false) +#test("abc".contains(regex("^[abc]$")), false) +#test("abc".contains(regex("^[abc]+$")), true) + +--- string-starts-with --- +// Test the `starts-with` and `ends-with` methods. +#test("Typst".starts-with("Ty"), true) +#test("Typst".starts-with(regex("[Tt]ys")), false) +#test("Typst".starts-with("st"), false) + +--- string-ends-with --- +#test("Typst".ends-with("st"), true) +#test("Typst".ends-with(regex("\d*")), true) +#test("Typst".ends-with(regex("\d+")), false) +#test("Typ12".ends-with(regex("\d+")), true) +#test("typst13".ends-with(regex("1[0-9]")), true) +#test("typst113".ends-with(regex("1[0-9]")), true) +#test("typst23".ends-with(regex("1[0-9]")), false) + +--- string-find-and-position --- +// Test the `find` and `position` methods. +#let date = regex("\d{2}:\d{2}") +#test("Hello World".find("World"), "World") +#test("Hello World".position("World"), 6) +#test("It's 12:13 now".find(date), "12:13") +#test("It's 12:13 now".position(date), 5) + +--- string-match --- +// Test the `match` method. +#test("Is there a".match("for this?"), none) +#test( + "The time of my life.".match(regex("[mit]+e")), + (start: 4, end: 8, text: "time", captures: ()), +) + +--- string-matches --- +// Test the `matches` method. +#test("Hello there".matches("\d"), ()) +#test("Day by Day.".matches("Day"), ( + (start: 0, end: 3, text: "Day", captures: ()), + (start: 7, end: 10, text: "Day", captures: ()), +)) + +// Compute the sum of all timestamps in the text. +#let timesum(text) = { + let time = 0 + for match in text.matches(regex("(\d+):(\d+)")) { + let caps = match.captures + time += 60 * int(caps.at(0)) + int(caps.at(1)) + } + str(int(time / 60)) + ":" + str(calc.rem(time, 60)) +} + +#test(timesum(""), "0:0") +#test(timesum("2:70"), "3:10") +#test(timesum("1:20, 2:10, 0:40"), "4:10") + +--- stgring-replace --- +// Test the `replace` method with `Str` replacements. +#test("ABC".replace("", "-"), "-A-B-C-") +#test("Ok".replace("Ok", "Nope", count: 0), "Ok") +#test("to add?".replace("", "How ", count: 1), "How to add?") +#test("AB C DEF GH J".replace(" ", ",", count: 2), "AB,C,DEF GH J") +#test("Walcemo" + .replace("o", "k") + .replace("e", "o") + .replace("k", "e") + .replace("a", "e"), + "Welcome" +) +#test("123".replace(regex("\d$"), "_"), "12_") +#test("123".replace(regex("\d{1,2}$"), "__"), "1__") + +--- string-replace-function --- +// Test the `replace` method with `Func` replacements. + +#test("abc".replace(regex("[a-z]"), m => { + str(m.start) + m.text + str(m.end) +}), "0a11b22c3") +#test("abcd, efgh".replace(regex("\w+"), m => { + upper(m.text) +}), "ABCD, EFGH") +#test("hello : world".replace(regex("^(.+)\s*(:)\s*(.+)$"), m => { + upper(m.captures.at(0)) + m.captures.at(1) + " " + upper(m.captures.at(2)) +}), "HELLO : WORLD") +#test("hello world, lorem ipsum".replace(regex("(\w+) (\w+)"), m => { + m.captures.at(1) + " " + m.captures.at(0) +}), "world hello, ipsum lorem") +#test("hello world, lorem ipsum".replace(regex("(\w+) (\w+)"), count: 1, m => { + m.captures.at(1) + " " + m.captures.at(0) +}), "world hello, lorem ipsum") +#test("123 456".replace(regex("[a-z]+"), "a"), "123 456") + +#test("abc".replace("", m => "-"), "-a-b-c-") +#test("abc".replace("", m => "-", count: 1), "-abc") +#test("123".replace("abc", m => ""), "123") +#test("123".replace("abc", m => "", count: 2), "123") +#test("a123b123c".replace("123", m => { + str(m.start) + "-" + str(m.end) +}), "a1-4b5-8c") +#test("halla warld".replace("a", m => { + if m.start == 1 { "e" } + else if m.start == 4 or m.start == 7 { "o" } +}), "hello world") +#test("aaa".replace("a", m => str(m.captures.len())), "000") + +--- string-replace-function-bad-type --- +// Error: 23-24 expected string, found integer +#"123".replace("123", m => 1) + +--- string-replace-bad-type --- +// Error: 23-32 expected string or function, found array +#"123".replace("123", (1, 2, 3)) + +--- string-trim-basic --- +// Test the `trim` method; the pattern is not provided. +#let str = "Typst, LaTeX, Word, InDesign" +#let array = ("Typst", "LaTeX", "Word", "InDesign") +#test(str.split(",").map(s => s.trim()), array) +#test("".trim(), "") +#test(" ".trim(), "") +#test("\t".trim(), "") +#test("\n".trim(), "") +#test("\t \n".trim(), "") +#test(" abc ".trim(at: start), "abc ") +#test("\tabc ".trim(at: start), "abc ") +#test("abc\n".trim(at: end), "abc") +#test(" abc ".trim(at: end, repeat: true), " abc") +#test(" abc".trim(at: start, repeat: false), "abc") + +--- string-trim-pattern-str --- +// Test the `trim` method; the pattern is a string. +#test("aabcaa".trim("a", repeat: false), "abca") +#test("aabca".trim("a", at: start), "bca") +#test("aabcaa".trim("a", at: end, repeat: false), "aabca") +#test(" abc\n".trim("\n"), " abc") +#test("whole".trim("whole", at: start), "") + +--- string-trim-pattern-regex --- +// Test the `trim` method; the pattern is a regex. +#test("".trim(regex(".")), "") +#test("123abc456".trim(regex("\d")), "abc") +#test("123abc456".trim(regex("\d"), repeat: false), "23abc45") +#test("123a4b5c678".trim(regex("\d"), repeat: true), "a4b5c") +#test("123a4b5c678".trim(regex("\d"), repeat: false), "23a4b5c67") +#test("123abc456".trim(regex("\d"), at: start), "abc456") +#test("123abc456".trim(regex("\d"), at: end), "123abc") +#test("123abc456".trim(regex("\d+"), at: end, repeat: false), "123abc") +#test("123abc456".trim(regex("\d{1,2}$"), repeat: false), "123abc4") +#test("hello world".trim(regex(".")), "") +#test("12306".trim(regex("\d"), at: start), "") +#test("12306abc".trim(regex("\d"), at: start), "abc") +#test("whole".trim(regex("whole"), at: start), "") +#test("12306".trim(regex("\d"), at: end), "") +#test("abc12306".trim(regex("\d"), at: end), "abc") +#test("whole".trim(regex("whole"), at: end), "") + +--- string-trim-at-bad-alignment --- +// Error: 17-21 expected either `start` or `end` +#"abc".trim(at: left) + +--- string-split --- +// Test the `split` method. +#test("abc".split(""), ("", "a", "b", "c", "")) +#test("abc".split("b"), ("a", "c")) +#test("a123c".split(regex("\d")), ("a", "", "", "c")) +#test("a123c".split(regex("\d+")), ("a", "c")) + +--- string-rev --- +// Test the `rev` method. +#test("abc".rev(), "cba") +#test("ax̂e".rev(), "ex̂a") + +--- string-unclosed --- +// Error: 2-2:1 unclosed string +#"hello\" diff --git a/tests/suite/foundations/type.typ b/tests/suite/foundations/type.typ new file mode 100644 index 00000000..f2a98845 --- /dev/null +++ b/tests/suite/foundations/type.typ @@ -0,0 +1,25 @@ +--- type --- +#test(type(1), int) +#test(type(ltr), direction) +#test(type(10 / 3), float) + +--- type-string-compatibility --- +#test(type(10), int) +#test(type(10), "integer") +#test("is " + type(10), "is integer") +#test(int in ("integer", "string"), true) +#test(int in "integers or strings", true) +#test(str in "integers or strings", true) + +--- issue-3110-type-constructor --- +// Let the error message report the type name. +// Error: 2-9 type content does not have a constructor +#content() + +--- issue-3110-associated-field --- +// Error: 6-12 type integer does not contain field `MAXVAL` +#int.MAXVAL + +--- issue-3110-associated-function --- +// Error: 6-18 type string does not contain field `from-unïcode` +#str.from-unïcode(97) diff --git a/tests/suite/foundations/version.typ b/tests/suite/foundations/version.typ new file mode 100644 index 00000000..bf2cadb1 --- /dev/null +++ b/tests/suite/foundations/version.typ @@ -0,0 +1,47 @@ +// Test versions. + +--- version-constructor --- +// Test version constructor. + +// Empty. +#version() + +// Plain. +#test(version(1, 2).major, 1) + +// Single Array argument. +#test(version((1, 2)).minor, 2) + +// Mixed arguments. +#test(version(1, (2, 3), 4, (5, 6), 7).at(5), 6) + +--- version-equality --- +// Test equality of different-length versions +#test(version(), version(0)) +#test(version(0), version(0, 0)) +#test(version(1, 2), version(1, 2, 0, 0, 0, 0)) + +--- version-at --- +// Test `version.at`. + +// Non-negative index in bounds +#test(version(1, 2).at(1), 2) + +// Non-negative index out of bounds +#test(version(1, 2).at(4), 0) + +// Negative index in bounds +#test(version(1, 2).at(-2), 1) + +// Error: 2-22 component index out of bounds (index: -3, len: 2) +#version(1, 2).at(-3) + +--- version-fields --- +// Test version fields. +#test(version(1, 2, 3).major, 1) +#test(version(1, 2, 3).minor, 2) +#test(version(1, 2, 3).patch, 3) + +--- version-type --- +// Test the type of `sys.version` +#test(type(sys.version), version) diff --git a/tests/suite/introspection/counter.typ b/tests/suite/introspection/counter.typ new file mode 100644 index 00000000..8a5315f9 --- /dev/null +++ b/tests/suite/introspection/counter.typ @@ -0,0 +1,78 @@ +// Test counters. + +--- counter-basic-1 --- +// Count with string key. +#let mine = counter("mine!") + +Final: #context mine.final().at(0) \ +#mine.step() +First: #context mine.display() \ +#mine.update(7) +#context mine.display("1 of 1", both: true) \ +#mine.step() +#mine.step() +Second: #context mine.display("I") +#mine.update(n => n * 2) +#mine.step() + +--- counter-basic-2 --- +// Test `counter`. +#let c = counter("heading") +#c.update(2) +#c.update(n => n + 2) +#context test(c.get(), (4,)) +#c.update(n => n - 3) +#context test(c.at(here()), (1,)) + +--- counter-label --- +// Count labels. +#let label = <heya> +#let count = context counter(label).display() +#let elem(it) = [#box(it) #label] + +#elem[hey, there!] #count \ +#elem[more here!] #count + +--- counter-heading --- +// Count headings. +#set heading(numbering: "1.a.") +#show heading: set text(10pt) +#counter(heading).step() + += Alpha +In #context counter(heading).display() +== Beta + +#set heading(numbering: none) += Gamma +#heading(numbering: "I.")[Delta] + +At Beta, it was #context { + let it = query(heading).find(it => it.body == [Beta]) + numbering(it.numbering, ..counter(heading).at(it.location())) +} + +--- counter-page --- +#set page(height: 50pt, margin: (bottom: 20pt, rest: 10pt)) +#lorem(12) +#set page(numbering: "(i)") +#lorem(6) +#pagebreak() +#set page(numbering: "1 / 1") +#counter(page).update(1) +#lorem(20) + +--- counter-figure --- +// Count figures. +#figure(numbering: "A", caption: [Four 'A's], kind: image, supplement: "Figure")[_AAAA!_] +#figure(numbering: none, caption: [Four 'B's], kind: image, supplement: "Figure")[_BBBB!_] +#figure(caption: [Four 'C's], kind: image, supplement: "Figure")[_CCCC!_] +#counter(figure.where(kind: image)).update(n => n + 3) +#figure(caption: [Four 'D's], kind: image, supplement: "Figure")[_DDDD!_] + +--- counter-at-no-context --- +// Test `counter.at` outside of context. +// Error: 2-28 can only be used when context is known +// Hint: 2-28 try wrapping this in a `context` expression +// Hint: 2-28 the `context` expression should wrap everything that depends on this function +#counter("key").at(<label>) diff --git a/tests/suite/introspection/here.typ b/tests/suite/introspection/here.typ new file mode 100644 index 00000000..18fff439 --- /dev/null +++ b/tests/suite/introspection/here.typ @@ -0,0 +1,3 @@ +--- here-position --- +// Test `context` + `here`. +#context test(here().position().y, 10pt) diff --git a/tests/suite/introspection/locate.typ b/tests/suite/introspection/locate.typ new file mode 100644 index 00000000..981f8c46 --- /dev/null +++ b/tests/suite/introspection/locate.typ @@ -0,0 +1,32 @@ +--- locate-position --- +// Test `locate`. +#v(10pt) += Introduction <intro> +#context test(locate(<intro>).position().y, 20pt) + +--- locate-missing-label --- +// Error: 10-25 label `<intro>` does not exist in the document +#context locate(<intro>) + +--- locate-duplicate-label --- += Introduction <intro> += Introduction <intro> + +// Error: 10-25 label `<intro>` occurs multiple times in the document +#context locate(<intro>) + +--- locate-element-selector --- +#v(10pt) += Introduction <intro> +#context test(locate(heading).position().y, 20pt) + +--- locate-element-selector-no-match --- +// Error: 10-25 selector does not match any element +#context locate(heading) + +--- locate-element-selector-multiple-matches --- += Introduction <intro> += Introduction <intro> + +// Error: 10-25 selector matches multiple elements +#context locate(heading) diff --git a/tests/suite/introspection/query.typ b/tests/suite/introspection/query.typ new file mode 100644 index 00000000..3a4b4fbf --- /dev/null +++ b/tests/suite/introspection/query.typ @@ -0,0 +1,267 @@ +// Test creating a header with the query function. + +--- query-here --- +// Test that `here()` yields the context element's location. +#context test(query(here()).first().func(), (context none).func()) + +--- query-running-header --- +#set page( + paper: "a8", + margin: (y: 1cm, x: 0.5cm), + header: context { + smallcaps[Typst Academy] + h(1fr) + let after = query(selector(heading).after(here())) + let before = query(selector(heading).before(here())) + let elem = if before.len() != 0 { + before.last() + } else if after.len() != 0 { + after.first() + } + emph(elem.body) + } +) + +#outline() + += Introduction +#v(1cm) + += Background +#v(2cm) + += Approach + +--- query-list-of-figures --- +#set page( + paper: "a8", + numbering: "1 / 1", + margin: (bottom: 1cm, rest: 0.5cm), +) + +#set figure(numbering: "I") +#show figure: set image(width: 80%) + += List of Figures +#context { + let elements = query(selector(figure).after(here())) + for it in elements [ + Figure + #numbering(it.numbering, + ..counter(figure).at(it.location())): + #it.caption.body + #box(width: 1fr, repeat[.]) + #counter(page).at(it.location()).first() \ + ] +} + +#figure( + image("/assets/images/cylinder.svg", width: 50%), + caption: [Cylinder], +) + +#figure( + rect[Just some stand-in text], + kind: image, + supplement: "Figure", + caption: [Stand-in text], +) + +#figure( + image("/assets/images/tetrahedron.svg", width: 50%), + caption: [Tetrahedron], +) + +--- query-before-after --- +// LARGE +#set page( + paper: "a7", + numbering: "1 / 1", + margin: (bottom: 1cm, rest: 0.5cm), +) + +#show heading.where(level: 1, outlined: true): it => [ + #it + + #set text(size: 12pt, weight: "regular") + #outline( + title: "Chapter outline", + indent: true, + target: heading + .where(level: 1) + .or(heading.where(level: 2)) + .after(it.location(), inclusive: true) + .before( + heading + .where(level: 1, outlined: true) + .after(it.location(), inclusive: false), + inclusive: false, + ) + ) +] + +#set heading(outlined: true, numbering: "1.") + += Section 1 +== Subsection 1 +== Subsection 2 +=== Subsubsection 1 +=== Subsubsection 2 +== Subsection 3 + += Section 2 +== Subsection 1 +== Subsection 2 + += Section 3 +== Subsection 1 +== Subsection 2 +=== Subsubsection 1 +=== Subsubsection 2 +=== Subsubsection 3 +== Subsection 3 + +--- query-and-or --- +#set page( + paper: "a7", + numbering: "1 / 1", + margin: (bottom: 1cm, rest: 0.5cm), +) + +#set heading(outlined: true, numbering: "1.") + +#context [ + Non-outlined elements: + #(query(selector(heading).and(heading.where(outlined: false))) + .map(it => it.body).join(", ")) +] + +#heading("A", outlined: false) +#heading("B", outlined: true) +#heading("C", outlined: true) +#heading("D", outlined: false) + +--- query-complex --- += A +== B +#figure([Cat], kind: "cat", supplement: [Other]) +=== D += E <first> +#figure([Frog], kind: "frog", supplement: none) +#figure([Giraffe], kind: "giraffe", supplement: none) <second> +#figure([GiraffeCat], kind: "cat", supplement: [Other]) <second> += H +#figure([Iguana], kind: "iguana", supplement: none) +== I + +#let test-selector(selector, ref) = context { + test(query(selector).map(e => e.body), ref) +} + +// Test `or`. +#test-selector( + heading.where(level: 1).or(heading.where(level: 3)), + ([A], [D], [E], [H]), +) + +#test-selector( + heading.where(level: 1).or( + heading.where(level: 3), + figure.where(kind: "frog"), + ), + ([A], [D], [E], [Frog], [H]), +) + +#test-selector( + heading.where(level: 1).or( + heading.where(level: 2), + figure.where(kind: "frog"), + figure.where(kind: "cat"), + ), + ([A], [B], [Cat], [E], [Frog], [GiraffeCat], [H], [I]), +) + +#test-selector( + figure.where(kind: "dog").or(heading.where(level: 3)), + ([D],), +) + +#test-selector( + figure.where(kind: "dog").or(figure.where(kind: "fish")), + (), +) + +// Test `or` duplicates removal. +#test-selector( + heading.where(level: 1).or(heading.where(level: 1)), + ([A], [E], [H]), +) + +// Test `and`. +#test-selector( + figure.where(kind: "cat").and(figure.where(kind: "frog")), + (), +) + +// Test `or` with `before`/`after` +#test-selector( + selector(heading) + .before(<first>) + .or(selector(figure).before(<first>)), + ([A], [B], [Cat], [D], [E]), +) + +#test-selector( + heading.where(level: 2) + .after(<first>) + .or(selector(figure).after(<first>)), + ([Frog], [Giraffe], [GiraffeCat], [Iguana], [I]), +) + +// Test `and` with `after` +#test-selector( + figure.where(kind: "cat") + .and(figure.where(supplement: [Other])) + .after(<first>), + ([GiraffeCat],), +) + +// Test `and` (with nested `or`) +#test-selector( + heading.where(level: 2) + .or(heading.where(level: 3)) + .and(heading.where(level: 2).or(heading.where(level: 1))), + ([B], [I]), +) + +#test-selector( + heading.where(level: 2) + .or(heading.where(level: 3), heading.where(level:1)) + .and( + heading.where(level: 2).or(heading.where(level: 1)), + heading.where(level: 3).or(heading.where(level: 1)), + ), + ([A], [E], [H]), +) + +// Test `and` with `or` and `before`/`after` +#test-selector( + heading.where(level: 1).before(<first>) + .or(heading.where(level: 3).before(<first>)) + .and( + heading.where(level: 1).before(<first>) + .or(heading.where(level: 2).before(<first>)) + ), + ([A], [E]), +) + +#test-selector( + heading.where(level: 1).before(<first>, inclusive: false) + .or(selector(figure).after(<first>)) + .and(figure.where(kind: "iguana").or( + figure.where(kind: "frog"), + figure.where(kind: "cat"), + heading.where(level: 1).after(<first>), + )), + ([Frog], [GiraffeCat], [Iguana]) +) diff --git a/tests/suite/introspection/state.typ b/tests/suite/introspection/state.typ new file mode 100644 index 00000000..208a4ea2 --- /dev/null +++ b/tests/suite/introspection/state.typ @@ -0,0 +1,63 @@ +// Test state. + +--- state-basic --- +#let s = state("hey", "a") +#let double(it) = 2 * it + +#s.update(double) +#s.update(double) +$ 2 + 3 $ +#s.update(double) + +Is: #context s.get(), +Was: #context { + let it = query(math.equation).first() + s.at(it.location()) +}. + +--- state-multiple-calls-same-key --- +// Try same key with different initial value. +#context state("key", 2).get() +#state("key").update(x => x + 1) +#context state("key", 2).get() +#context state("key", 3).get() +#state("key").update(x => x + 1) +#context state("key", 2).get() + +--- state-nested --- +#set page(width: 200pt) +#set text(8pt) + +#let ls = state("lorem", lorem(1000).split(".")) +#let loremum(count) = { + context ls.get().slice(0, count).join(".").trim() + "." + ls.update(list => list.slice(count)) +} + +#let fs = state("fader", red) +#let trait(title) = block[ + #context text(fill: fs.get())[ + *#title:* #loremum(1) + ] + #fs.update(color => color.lighten(30%)) +] + +#trait[Boldness] +#trait[Adventure] +#trait[Fear] +#trait[Anger] + +--- state-no-convergence --- +// Make sure that a warning is produced if the layout fails to converge. +// Warning: layout did not converge within 5 attempts +// Hint: check if any states or queries are updating themselves +#let s = state("s", 1) +#context s.update(s.final() + 1) +#context s.get() + +--- state-at-no-context --- +// Test `state.at` outside of context. +// Error: 2-26 can only be used when context is known +// Hint: 2-26 try wrapping this in a `context` expression +// Hint: 2-26 the `context` expression should wrap everything that depends on this function +#state("key").at(<label>) diff --git a/tests/suite/layout/align.typ b/tests/suite/layout/align.typ new file mode 100644 index 00000000..61b79975 --- /dev/null +++ b/tests/suite/layout/align.typ @@ -0,0 +1,142 @@ +// Test alignment. + +--- align-right --- +// Test ragged-left. +#set align(right) +To the right! Where the sunlight peeks behind the mountain. + +--- align-in-stack --- +#set page(height: 100pt) +#stack(dir: ltr, + align(left, square(size: 15pt, fill: eastern)), + align(center, square(size: 20pt, fill: eastern)), + align(right, square(size: 15pt, fill: eastern)), +) +#align(center + horizon, rect(fill: eastern, height: 10pt)) +#align(bottom, stack( + align(center, rect(fill: conifer, height: 10pt)), + rect(fill: forest, height: 10pt, width: 100%), +)) + +--- align-center-in-flow --- +// Test that multiple paragraphs in subflow also respect alignment. +#align(center)[ + Lorem Ipsum + + Dolor +] + +--- align-start-and-end --- +// Test start and end alignment. +#rotate(-30deg, origin: end + horizon)[Hello] + +#set text(lang: "de") +#align(start)[Start] +#align(end)[Ende] + +#set text(lang: "ar") +#align(start)[يبدأ] +#align(end)[نهاية] + +--- alignment-fields-x --- +// Test 2d alignment 'horizontal' field. +#test((start + top).x, start) +#test((end + top).x, end) +#test((left + top).x, left) +#test((right + top).x, right) +#test((center + top).x, center) +#test((start + bottom).x, start) +#test((end + bottom).x, end) +#test((left + bottom).x, left) +#test((right + bottom).x, right) +#test((center + bottom).x, center) +#test((start + horizon).x, start) +#test((end + horizon).x, end) +#test((left + horizon).x, left) +#test((right + horizon).x, right) +#test((center + horizon).x, center) +#test((top + start).x, start) +#test((bottom + end).x, end) +#test((horizon + center).x, center) + +--- alignment-fields-y --- +// Test 2d alignment 'vertical' field. +#test((start + top).y, top) +#test((end + top).y, top) +#test((left + top).y, top) +#test((right + top).y, top) +#test((center + top).y, top) +#test((start + bottom).y, bottom) +#test((end + bottom).y, bottom) +#test((left + bottom).y, bottom) +#test((right + bottom).y, bottom) +#test((center + bottom).y, bottom) +#test((start + horizon).y, horizon) +#test((end + horizon).y, horizon) +#test((left + horizon).y, horizon) +#test((right + horizon).y, horizon) +#test((center + horizon).y, horizon) +#test((top + start).y, top) +#test((bottom + end).y, bottom) +#test((horizon + center).y, horizon) + +--- alignment-type --- +#test(type(center), alignment) +#test(type(horizon), alignment) +#test(type(center + horizon), alignment) + +--- alignment-axis --- +// Test alignment methods. +#test(start.axis(), "horizontal") +#test(end.axis(), "horizontal") +#test(left.axis(), "horizontal") +#test(right.axis(), "horizontal") +#test(center.axis(), "horizontal") +#test(top.axis(), "vertical") +#test(bottom.axis(), "vertical") +#test(horizon.axis(), "vertical") + +--- alignment-inv --- +#test(start.inv(), end) +#test(end.inv(), start) +#test(left.inv(), right) +#test(right.inv(), left) +#test(center.inv(), center) +#test(top.inv(), bottom) +#test(bottom.inv(), top) +#test(horizon.inv(), horizon) +#test((start + top).inv(), (end + bottom)) +#test((end + top).inv(), (start + bottom)) +#test((left + top).inv(), (right + bottom)) +#test((right + top).inv(), (left + bottom)) +#test((center + top).inv(), (center + bottom)) +#test((start + bottom).inv(), (end + top)) +#test((end + bottom).inv(), (start + top)) +#test((left + bottom).inv(), (right + top)) +#test((right + bottom).inv(), (left + top)) +#test((center + bottom).inv(), (center + top)) +#test((start + horizon).inv(), (end + horizon)) +#test((end + horizon).inv(), (start + horizon)) +#test((left + horizon).inv(), (right + horizon)) +#test((right + horizon).inv(), (left + horizon)) +#test((center + horizon).inv(), (center + horizon)) +#test((top + start).inv(), (end + bottom)) +#test((bottom + end).inv(), (start + top)) +#test((horizon + center).inv(), (center + horizon)) + +--- alignment-add-two-horizontal --- +// Error: 8-22 cannot add two horizontal alignments +#align(center + right, [A]) + +--- alignment-add-two-vertical --- +// Error: 8-20 cannot add two vertical alignments +#align(top + bottom, [A]) + +--- alignment-add-vertical-and-2d --- +// Error: 8-30 cannot add a vertical and a 2D alignment +#align(top + (bottom + right), [A]) + +--- issue-1398-line-align --- +// Test right-aligning a line and a rectangle. +#align(right, line(length: 30%)) +#align(right, rect()) diff --git a/tests/suite/layout/angle.typ b/tests/suite/layout/angle.typ new file mode 100644 index 00000000..65e80aeb --- /dev/null +++ b/tests/suite/layout/angle.typ @@ -0,0 +1,8 @@ +--- angle-to-unit --- +// Test angle methods. +#test(1rad.rad(), 1.0) +#test(1.23rad.rad(), 1.23) +#test(0deg.rad(), 0.0) +#test(2deg.deg(), 2.0) +#test(2.94deg.deg(), 2.94) +#test(0rad.deg(), 0.0) diff --git a/tests/typ/empty.typ b/tests/suite/layout/clip.typ index e69de29b..e69de29b 100644 --- a/tests/typ/empty.typ +++ b/tests/suite/layout/clip.typ diff --git a/tests/suite/layout/columns.typ b/tests/suite/layout/columns.typ new file mode 100644 index 00000000..87a9f773 --- /dev/null +++ b/tests/suite/layout/columns.typ @@ -0,0 +1,124 @@ +// Test the column layouter. + +--- columns-rtl --- +// Test normal operation and RTL directions. +#set page(height: 3.25cm, width: 7.05cm, columns: 2) +#set text(lang: "ar", font: ("Noto Sans Arabic", "Linux Libertine")) +#set columns(gutter: 30pt) + +#box(fill: conifer, height: 8pt, width: 6pt) وتحفيز +العديد من التفاعلات الكيميائية. (DNA) من أهم الأحماض النووية التي تُشكِّل +إلى جانب كل من البروتينات والليبيدات والسكريات المتعددة +#box(fill: eastern, height: 8pt, width: 6pt) +الجزيئات الضخمة الأربعة الضرورية للحياة. + +--- columns-in-fixed-size-rect --- +// Test the `columns` function. +#set page(width: auto) + +#rect(width: 180pt, height: 100pt, inset: 8pt, columns(2, [ + A special plight has befallen our document. + Columns in text boxes reigned down unto the soil + to waste a year's crop of rich layouts. + The columns at least were graciously balanced. +])) + +--- columns-set-page --- +// Test columns for a sized page. +#set page(height: 5cm, width: 7.05cm, columns: 2) + +Lorem ipsum dolor sit amet is a common blind text +and I again am in need of filling up this page +#align(bottom, rect(fill: eastern, width: 100%, height: 12pt)) +#colbreak() + +so I'm returning to this trusty tool of tangible terror. +Sure, it is not the most creative way of filling up +a page for a test but it does get the job done. + +--- columns-in-auto-sized-rect --- +// Test the expansion behaviour. +#set page(height: 2.5cm, width: 7.05cm) + +#rect(inset: 6pt, columns(2, [ + ABC \ + BCD + #colbreak() + DEF +])) + +--- columns-more-with-gutter --- +// Test setting a column gutter and more than two columns. +#set page(height: 3.25cm, width: 7.05cm, columns: 3) +#set columns(gutter: 30pt) + +#rect(width: 100%, height: 2.5cm, fill: conifer) #parbreak() +#rect(width: 100%, height: 2cm, fill: eastern) #parbreak() +#circle(fill: eastern) + +--- columns-set-page-colbreak-pagebreak --- +// Test the `colbreak` and `pagebreak` functions. +#set page(height: 1cm, width: 7.05cm, columns: 2) + +A +#colbreak() +#colbreak() +B +#pagebreak() +C +#colbreak() +D + +--- columns-empty-second-column --- +// Test an empty second column. +#set page(width: 7.05cm, columns: 2) + +#rect(width: 100%, inset: 3pt)[So there isn't anything in the second column?] + +--- columns-page-width-auto --- +// Test columns when one of them is empty. +#set page(width: auto, columns: 3) + +Arbitrary horizontal growth. + +--- columns-page-height-auto --- +// Test columns in an infinitely high frame. +#set page(width: 7.05cm, columns: 2) + +There can be as much content as you want in the left column +and the document will grow with it. + +#rect(fill: conifer, width: 100%, height: 30pt) + +Only an explicit #colbreak() `#colbreak()` can put content in the +second column. + +--- columns-one --- +// Test a page with a single column. +#set page(height: auto, width: 7.05cm, columns: 1) + +This is a normal page. Very normal. + +--- columns-zero --- +// Test a page with zero columns. +// Error: 49-50 number must be positive +#set page(height: auto, width: 7.05cm, columns: 0) + +--- columns-colbreak-after-place --- +// Test colbreak after only out-of-flow elements. +#set page(width: 7.05cm, columns: 2) +#place[OOF] +#colbreak() +In flow. + +--- issue-columns-heading --- +// The well-known columns bug. +#set page(height: 70pt) + +Hallo +#columns(2)[ + = A + Text + = B + Text +] diff --git a/tests/suite/layout/container.typ b/tests/suite/layout/container.typ new file mode 100644 index 00000000..ede051db --- /dev/null +++ b/tests/suite/layout/container.typ @@ -0,0 +1,183 @@ +// Test the `box` and `block` containers. + +--- box --- +// Test box in paragraph. +A #box[B \ C] D. + +// Test box with height. +Spaced \ +#box(height: 0.5cm) \ +Apart + +--- block-sizing --- +// Test block sizing. +#set page(height: 120pt) +#set block(spacing: 0pt) +#block(width: 90pt, height: 80pt, fill: red)[ + #block(width: 60%, height: 60%, fill: green) + #block(width: 50%, height: 60%, fill: blue) +] + +--- box-layoutable-child --- +// Test box sizing with layoutable child. +#box( + width: 50pt, + height: 50pt, + fill: yellow, + path( + fill: purple, + (0pt, 0pt), + (30pt, 30pt), + (0pt, 30pt), + (30pt, 0pt), + ), +) + +--- box-width-fr --- +// Test fr box. +Hello #box(width: 1fr, rect(height: 0.7em, width: 100%)) World + +--- block-multiple-pages --- +// Test block over multiple pages. +#set page(height: 60pt) + +First! + +#block[ + But, soft! what light through yonder window breaks? It is the east, and Juliet + is the sun. +] + +--- block-box-fill --- +#set page(height: 100pt) +#let words = lorem(18).split() +#block(inset: 8pt, width: 100%, fill: aqua, stroke: aqua.darken(30%))[ + #words.slice(0, 13).join(" ") + #box(fill: teal, outset: 2pt)[tempor] + #words.slice(13).join(" ") +] + +--- block-spacing-basic --- +#set block(spacing: 10pt) +Hello + +There + +#block(spacing: 20pt)[Further down] + +--- block-spacing-table --- +// Test that paragraph spacing loses against block spacing. +// TODO +#set block(spacing: 100pt) +#show table: set block(above: 5pt, below: 5pt) +Hello +#table(columns: 4, fill: (x, y) => if calc.odd(x + y) { silver })[A][B][C][D] + +--- block-spacing-maximum --- +// While we're at it, test the larger block spacing wins. +#set block(spacing: 0pt) +#show raw: set block(spacing: 15pt) +#show list: set block(spacing: 2.5pt) + +```rust +fn main() {} +``` + +- List + +Paragraph + +--- block-spacing-collapse-text-style --- +// Test spacing collapsing with different font sizes. +#grid(columns: 2)[ + #text(size: 12pt, block(below: 1em)[A]) + #text(size: 8pt, block(above: 1em)[B]) +][ + #text(size: 12pt, block(below: 1em)[A]) + #text(size: 8pt, block(above: 1.25em)[B]) +] + +--- block-fixed-height --- +#set page(height: 100pt) +#set align(center) + +#lorem(10) +#block(width: 80%, height: 60pt, fill: aqua) +#lorem(6) +#block( + breakable: false, + width: 100%, + inset: 4pt, + fill: aqua, + lorem(8) + colbreak(), +) + +--- box-clip-rect --- +// Test box clipping with a rectangle +Hello #box(width: 1em, height: 1em, clip: false)[#rect(width: 3em, height: 3em, fill: red)] +world 1 + +Space + +Hello #box(width: 1em, height: 1em, clip: true)[#rect(width: 3em, height: 3em, fill: red)] +world 2 + +--- block-clip-text --- +// Test cliping text +#block(width: 5em, height: 2em, clip: false, stroke: 1pt + black)[ + But, soft! what light through +] + +#v(2em) + +#block(width: 5em, height: 2em, clip: true, stroke: 1pt + black)[ + But, soft! what light through yonder window breaks? It is the east, and Juliet + is the sun. +] + +--- block-clip-svg-glyphs --- +// Test clipping svg glyphs +Emoji: #box(height: 0.5em, stroke: 1pt + black)[🐪, 🌋, 🏞] + +Emoji: #box(height: 0.5em, clip: true, stroke: 1pt + black)[🐪, 🌋, 🏞] + +--- block-clipping-multiple-pages --- +// Test block clipping over multiple pages. +#set page(height: 60pt) + +First! + +#block(height: 4em, clip: true, stroke: 1pt + black)[ + But, soft! what light through yonder window breaks? It is the east, and Juliet + is the sun. +] + +--- box-clip-radius --- +// Test clipping with `radius`. +#set page(height: 60pt) + +#box( + radius: 5pt, + stroke: 2pt + black, + width: 20pt, + height: 20pt, + clip: true, + image("/assets/images/rhino.png", width: 30pt) +) + +--- box-clip-radius-without-stroke --- +// Test clipping with `radius`, but without `stroke`. +#set page(height: 60pt) + +#box( + radius: 5pt, + width: 20pt, + height: 20pt, + clip: true, + image("/assets/images/rhino.png", width: 30pt) +) + +--- issue-2128-block-width-box --- +// Test box in 100% width block. +#block(width: 100%, fill: red, box("a box")) +#block(width: 100%, fill: red, [#box("a box") #box()]) diff --git a/tests/suite/layout/dir.typ b/tests/suite/layout/dir.typ new file mode 100644 index 00000000..139a2285 --- /dev/null +++ b/tests/suite/layout/dir.typ @@ -0,0 +1,24 @@ +--- dir-axis --- +// Test direction methods. +#test(ltr.axis(), "horizontal") +#test(rtl.axis(), "horizontal") +#test(ttb.axis(), "vertical") +#test(btt.axis(), "vertical") + +--- dir-start --- +#test(ltr.start(), left) +#test(rtl.start(), right) +#test(ttb.start(), top) +#test(btt.start(), bottom) + +--- dir-end --- +#test(ltr.end(), right) +#test(rtl.end(), left) +#test(ttb.end(), bottom) +#test(btt.end(), top) + +--- dir-inv --- +#test(ltr.inv(), rtl) +#test(rtl.inv(), ltr) +#test(ttb.inv(), btt) +#test(btt.inv(), ttb) diff --git a/tests/suite/layout/flow/flow.typ b/tests/suite/layout/flow/flow.typ new file mode 100644 index 00000000..9c48c9ac --- /dev/null +++ b/tests/suite/layout/flow/flow.typ @@ -0,0 +1,67 @@ +--- flow-fr --- +#set page(height: 2cm) +#set text(white) +#rect(fill: forest)[ + #v(1fr) + #h(1fr) Hi you! +] + +--- issue-flow-overlarge-frames --- +// In this bug, the first line of the second paragraph was on its page alone an +// the rest moved down. The reason was that the second block resulted in +// overlarge frames because the region wasn't finished properly. +#set page(height: 70pt) +#block[This file tests a bug where an almost empty page occurs.] +#block[ + The text in this second block was torn apart and split up for + some reason beyond my knowledge. +] + +--- issue-flow-trailing-leading --- +// In this bug, the first part of the paragraph moved down to the second page +// because trailing leading wasn't trimmed, resulting in an overlarge frame. +#set page(height: 60pt) +#v(19pt) +#block[ + But, soft! what light through yonder window breaks? + It is the east, and Juliet is the sun. +] + +--- issue-flow-weak-spacing --- +// In this bug, there was a bit of space below the heading because weak spacing +// directly before a layout-induced column or page break wasn't trimmed. +#set page(height: 60pt) +#rect(inset: 0pt, columns(2)[ + Text + #v(12pt) + Hi + #v(10pt, weak: true) + At column break. +]) + +--- issue-flow-frame-placement --- +// In this bug, a frame intended for the second region ended up in the first. +#set page(height: 105pt) +#block(lorem(20)) + +--- issue-flow-layout-index-out-of-bounds --- +// This bug caused an index-out-of-bounds panic when layouting paragraphs needed +// multiple reorderings. +#set page(height: 200pt) +#lorem(30) + +#figure(placement: auto, block(height: 100%)) + +#lorem(10) + +#lorem(10) + +--- issue-3641-float-loop --- +// Flow layout should terminate! +// +// This is not yet ideal: The heading should not move to the second page, but +// that's a separate bug and not a regression. +#set page(height: 40pt) + += Heading +#lorem(6) diff --git a/tests/suite/layout/flow/invisibles.typ b/tests/suite/layout/flow/invisibles.typ new file mode 100644 index 00000000..7e460373 --- /dev/null +++ b/tests/suite/layout/flow/invisibles.typ @@ -0,0 +1,61 @@ +// Test out-of-flow items (place, counter updates, etc.) at the +// beginning of a block not creating a frame just for them. + +--- flow-first-region-no-item --- +// No item in the first region. +#set page(height: 5cm, margin: 1cm) +No item in the first region. +#block(breakable: true, stroke: 1pt, inset: 0.5cm)[ + #rect(height: 2cm, fill: gray) +] + +--- flow-first-region-counter-update --- +// Counter update in the first region. +#set page(height: 5cm, margin: 1cm) +Counter update. +#block(breakable: true, stroke: 1pt, inset: 0.5cm)[ + #counter("dummy").step() + #rect(height: 2cm, fill: gray) +] + +--- flow-first-region-placed --- +// Placed item in the first region. +#set page(height: 5cm, margin: 1cm) +Placed item in the first region. +#block(breakable: true, above: 1cm, stroke: 1pt, inset: 0.5cm)[ + #place(dx: -0.5cm, dy: -0.75cm, box(width: 200%)[OOF]) + #rect(height: 2cm, fill: gray) +] + +--- flow-first-region-zero-sized-item --- +// In-flow item with size zero in the first region. +#set page(height: 5cm, margin: 1cm) +In-flow, zero-sized item. +#block(breakable: true, stroke: 1pt, inset: 0.5cm)[ + #set block(spacing: 0pt) + #line(length: 0pt) + #rect(height: 2cm, fill: gray) + #line(length: 100%) +] + +--- flow-first-region-counter-update-and-placed --- +// Counter update and placed item in the first region. +#set page(height: 5cm, margin: 1cm) +Counter update + place. +#block(breakable: true, above: 1cm, stroke: 1pt, inset: 0.5cm)[ + #counter("dummy").step() + #place(dx: -0.5cm, dy: -0.75cm, box([OOF])) + #rect(height: 2cm, fill: gray) +] + +--- flow-first-region-counter-update-placed-and-line --- +// Mix-and-match all the previous ones. +#set page(height: 5cm, margin: 1cm) +Mix-and-match all the previous tests. +#block(breakable: true, above: 1cm, stroke: 1pt, inset: 0.5cm)[ + #counter("dummy").step() + #place(dx: -0.5cm, dy: -0.75cm, box(width: 200%)[OOF]) + #line(length: 100%) + #place(dy: -0.8em)[OOF] + #rect(height: 2cm, fill: gray) +] diff --git a/tests/suite/layout/flow/orphan.typ b/tests/suite/layout/flow/orphan.typ new file mode 100644 index 00000000..70eac731 --- /dev/null +++ b/tests/suite/layout/flow/orphan.typ @@ -0,0 +1,31 @@ +// Test that lines and headings doesn't become orphan. + +--- flow-heading-no-orphan --- +#set page(height: 100pt) +#lorem(12) + += Introduction +This is the start and it goes on. + +--- flow-par-no-orphan-and-widow-lines --- +// LARGE +#set page("a8", height: 140pt) +#set text(weight: 700) + +// Fits fully onto the first page. +#set text(blue) +#lorem(27) + +// The first line would fit, but is moved to the second page. +#lorem(20) + +// The second-to-last line is moved to the third page so that the last is isn't +// as lonely. +#set text(maroon) +#lorem(11) + +#lorem(13) + +// All three lines go to the next page. +#set text(olive) +#lorem(10) diff --git a/tests/suite/layout/grid/cell.typ b/tests/suite/layout/grid/cell.typ new file mode 100644 index 00000000..3b08c752 --- /dev/null +++ b/tests/suite/layout/grid/cell.typ @@ -0,0 +1,132 @@ +// Test basic styling using the grid.cell element. + +--- grid-cell-override --- +// Cell override +#grid( + align: left, + fill: red, + stroke: blue, + inset: 5pt, + columns: 2, + [AAAAA], [BBBBB], + [A], [B], + grid.cell(align: right)[C], [D], + align(right)[E], [F], + align(horizon)[G], [A\ A\ A], + grid.cell(align: horizon)[G2], [A\ A\ A], + grid.cell(inset: 0pt)[I], [F], + [H], grid.cell(fill: blue)[J] +) + +--- grid-cell-show --- +// Cell show rule +#show grid.cell: it => [Zz] + +#grid( + align: left, + fill: red, + stroke: blue, + inset: 5pt, + columns: 2, + [AAAAA], [BBBBB], + [A], [B], + grid.cell(align: right)[C], [D], + align(right)[E], [F], + align(horizon)[G], [A\ A\ A] +) + +--- grid-cell-show-and-override --- +#show grid.cell: it => (it.align, it.fill) +#grid( + align: left, + row-gutter: 5pt, + [A], + grid.cell(align: right)[B], + grid.cell(fill: aqua)[B], +) + +--- grid-cell-set --- +// Cell set rules +#set grid.cell(align: center) +#show grid.cell: it => (it.align, it.fill, it.inset) +#set grid.cell(inset: 20pt) +#grid( + align: left, + row-gutter: 5pt, + [A], + grid.cell(align: right)[B], + grid.cell(fill: aqua)[B], +) + +--- grid-cell-folding --- +// Test folding per-cell properties (align and inset) +#grid( + columns: (1fr, 1fr), + rows: (2.5em, auto), + align: right, + inset: 5pt, + fill: (x, y) => (green, aqua).at(calc.rem(x + y, 2)), + [Top], grid.cell(align: bottom)[Bot], + grid.cell(inset: (bottom: 0pt))[Bot], grid.cell(inset: (bottom: 0pt))[Bot] +) + +--- grid-cell-align-override --- +// Test overriding outside alignment +#set align(bottom + right) +#grid( + columns: (1fr, 1fr), + rows: 2em, + align: auto, + fill: green, + [BR], [BR], + grid.cell(align: left, fill: aqua)[BL], grid.cell(align: top, fill: red.lighten(50%))[TR] +) + +--- grid-cell-various-overrides --- +#grid( + columns: 2, + fill: red, + align: left, + inset: 5pt, + [ABC], [ABC], + grid.cell(fill: blue)[C], [D], + grid.cell(align: center)[E], [F], + [G], grid.cell(inset: 0pt)[H] +) + +--- grid-cell-show-emph --- +#{ + show grid.cell: emph + grid( + columns: 2, + gutter: 3pt, + [Hello], [World], + [Sweet], [Italics] + ) +} + +--- grid-cell-show-based-on-position --- +// Style based on position +#{ + show grid.cell: it => { + if it.y == 0 { + strong(it) + } else if it.x == 1 { + emph(it) + } else { + it + } + } + grid( + columns: 3, + gutter: 3pt, + [Name], [Age], [Info], + [John], [52], [Nice], + [Mary], [50], [Cool], + [Jake], [49], [Epic] + ) +} + +--- table-cell-in-grid --- +// Error: 7-19 cannot use `table.cell` as a grid cell; use `grid.cell` instead +#grid(table.cell[]) diff --git a/tests/suite/layout/grid/colspan.typ b/tests/suite/layout/grid/colspan.typ new file mode 100644 index 00000000..707a9456 --- /dev/null +++ b/tests/suite/layout/grid/colspan.typ @@ -0,0 +1,142 @@ +--- grid-colspan --- +#grid( + columns: 4, + fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, + inset: 5pt, + align: center, + grid.cell(colspan: 4)[*Full Header*], + grid.cell(colspan: 2, fill: orange)[*Half*], + grid.cell(colspan: 2, fill: orange.darken(10%))[*Half*], + [*A*], [*B*], [*C*], [*D*], + [1], [2], [3], [4], + [5], grid.cell(colspan: 3, fill: orange.darken(10%))[6], + grid.cell(colspan: 2, fill: orange)[7], [8], [9], + [10], grid.cell(colspan: 2, fill: orange.darken(10%))[11], [12] +) + +#table( + columns: 4, + fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, + inset: 5pt, + align: center, + table.cell(colspan: 4)[*Full Header*], + table.cell(colspan: 2, fill: orange)[*Half*], + table.cell(colspan: 2, fill: orange.darken(10%))[*Half*], + [*A*], [*B*], [*C*], [*D*], + [1], [2], [3], [4], + [5], table.cell(colspan: 3, fill: orange.darken(10%))[6], + table.cell(colspan: 2, fill: orange)[7], [8], [9], + [10], table.cell(colspan: 2, fill: orange.darken(10%))[11], [12] +) + +--- grid-colspan-gutter --- +#grid( + columns: 4, + fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, + inset: 5pt, + align: center, + gutter: 3pt, + grid.cell(colspan: 4)[*Full Header*], + grid.cell(colspan: 2, fill: orange)[*Half*], + grid.cell(colspan: 2, fill: orange.darken(10%))[*Half*], + [*A*], [*B*], [*C*], [*D*], + [1], [2], [3], [4], + [5], grid.cell(colspan: 3, fill: orange.darken(10%))[6], + grid.cell(colspan: 2, fill: orange)[7], [8], [9], + [10], grid.cell(colspan: 2, fill: orange.darken(10%))[11], [12] +) + +#table( + columns: 4, + fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, + inset: 5pt, + align: center, + gutter: 3pt, + table.cell(colspan: 4)[*Full Header*], + table.cell(colspan: 2, fill: orange)[*Half*], + table.cell(colspan: 2, fill: orange.darken(10%))[*Half*], + [*A*], [*B*], [*C*], [*D*], + [1], [2], [3], [4], + [5], table.cell(colspan: 3, fill: orange.darken(10%))[6], + table.cell(colspan: 2, fill: orange)[7], [8], [9], + [10], table.cell(colspan: 2, fill: orange.darken(10%))[11], [12] +) + +--- grid-colspan-thick-stroke --- +#set page(width: 300pt) +#table( + columns: (2em, 2em, auto, auto), + stroke: 5pt, + [A], [B], [C], [D], + table.cell(colspan: 4, lorem(20)), + [A], table.cell(colspan: 2)[BCBCBCBC], [D] +) + +--- grid-colspan-out-of-bounds --- +// Error: 3:8-3:32 cell's colspan would cause it to exceed the available column(s) +// Hint: 3:8-3:32 try placing the cell in another position or reducing its colspan +#grid( + columns: 3, + [a], grid.cell(colspan: 3)[b] +) + +--- grid-colspan-overlap --- +// Error: 4:8-4:32 cell would span a previously placed cell at column 2, row 0 +// Hint: 4:8-4:32 try specifying your cells in a different order or reducing the cell's rowspan or colspan +#grid( + columns: 3, + grid.cell(x: 2, y: 0)[x], + [a], grid.cell(colspan: 2)[b] +) + +--- grid-colspan-over-all-fr-columns --- +// Colspan over all fractional columns shouldn't expand auto columns on finite pages +#table( + columns: (1fr, 1fr, auto), + [A], [B], [C], + [D], [E], [F] +) +#table( + columns: (1fr, 1fr, auto), + table.cell(colspan: 3, lorem(8)), + [A], [B], [C], + [D], [E], [F] +) + +--- grid-colspan-over-some-fr-columns --- +// Colspan over only some fractional columns will not trigger the heuristic, and +// the auto column will expand more than it should. The table looks off, as a result. +#table( + columns: (1fr, 1fr, auto), + [], table.cell(colspan: 2, lorem(8)), + [A], [B], [C], + [D], [E], [F] +) + +--- grid-colspan-over-all-fr-columns-page-width-auto --- +// On infinite pages, colspan over all fractional columns SHOULD expand auto columns +#set page(width: auto) +#table( + columns: (1fr, 1fr, auto), + [A], [B], [C], + [D], [E], [F] +) +#table( + columns: (1fr, 1fr, auto), + table.cell(colspan: 3, lorem(8)), + [A], [B], [C], + [D], [E], [F] +) + +--- grid-colspan-multiple-regions --- +// Test multiple regions +#set page(height: 5em) +#grid( + stroke: red, + fill: aqua, + columns: 4, + [a], [b], [c], [d], + [a], grid.cell(colspan: 2)[e, f, g, h, i], [f], + [e], [g], grid.cell(colspan: 2)[eee\ e\ e\ e], + grid.cell(colspan: 4)[eeee e e e] +) diff --git a/tests/suite/layout/grid/footers.typ b/tests/suite/layout/grid/footers.typ new file mode 100644 index 00000000..c73bcb39 --- /dev/null +++ b/tests/suite/layout/grid/footers.typ @@ -0,0 +1,404 @@ +--- grid-footer --- +#set page(width: auto, height: 15em) +#set text(6pt) +#set table(inset: 2pt, stroke: 0.5pt) +#table( + columns: 5, + align: center + horizon, + table.header( + table.cell(colspan: 5)[*Cool Zone*], + table.cell(stroke: red)[*Name*], table.cell(stroke: aqua)[*Number*], [*Data 1*], [*Data 2*], [*Etc*], + table.hline(start: 2, end: 3, stroke: yellow) + ), + ..range(0, 5).map(i => ([John \##i], table.cell(stroke: green)[123], table.cell(stroke: blue)[456], [789], [?], table.hline(start: 4, end: 5, stroke: red))).flatten(), + table.footer( + table.hline(start: 2, end: 3, stroke: yellow), + table.cell(stroke: red)[*Name*], table.cell(stroke: aqua)[*Number*], [*Data 1*], [*Data 2*], [*Etc*], + table.cell(colspan: 5)[*Cool Zone*] + ) +) + +--- grid-footer-gutter-and-no-repeat --- +// Gutter & no repetition +#set page(width: auto, height: 16em) +#set text(6pt) +#set table(inset: 2pt, stroke: 0.5pt) +#table( + columns: 5, + gutter: 2pt, + align: center + horizon, + table.header( + table.cell(colspan: 5)[*Cool Zone*], + table.cell(stroke: red)[*Name*], table.cell(stroke: aqua)[*Number*], [*Data 1*], [*Data 2*], [*Etc*], + table.hline(start: 2, end: 3, stroke: yellow) + ), + ..range(0, 5).map(i => ([John \##i], table.cell(stroke: green)[123], table.cell(stroke: blue)[456], [789], [?], table.hline(start: 4, end: 5, stroke: red))).flatten(), + table.footer( + repeat: false, + table.hline(start: 2, end: 3, stroke: yellow), + table.cell(stroke: red)[*Name*], table.cell(stroke: aqua)[*Number*], [*Data 1*], [*Data 2*], [*Etc*], + table.cell(colspan: 5)[*Cool Zone*] + ) +) + +--- grid-cell-override-in-header-and-footer --- +#table( + table.header(table.cell(stroke: red)[Hello]), + table.footer(table.cell(stroke: aqua)[Bye]), +) + +--- grid-cell-override-in-header-and-footer-with-gutter --- +#table( + gutter: 3pt, + table.header(table.cell(stroke: red)[Hello]), + table.footer(table.cell(stroke: aqua)[Bye]), +) + +--- grid-footer-top-stroke --- +// Footer's top stroke should win when repeated, but lose at the last page. +#set page(height: 10em) +#table( + stroke: green, + table.header(table.cell(stroke: red)[Hello]), + table.cell(stroke: yellow)[Hi], + table.cell(stroke: yellow)[Bye], + table.cell(stroke: yellow)[Ok], + table.footer[Bye], +) + +--- grid-footer-relative-row-sizes --- +// Relative lengths +#set page(height: 10em) +#table( + rows: (30%, 30%, auto), + [C], + [C], + table.footer[*A*][*B*], +) + +--- grid-footer-cell-with-y --- +#grid( + grid.footer(grid.cell(y: 2)[b]), + grid.cell(y: 0)[a], + grid.cell(y: 1)[c], +) + +--- grid-footer-expand --- +// Ensure footer properly expands +#grid( + columns: 2, + [a], [], + [b], [], + grid.cell(x: 1, y: 3, rowspan: 4)[b], + grid.cell(y: 2, rowspan: 2)[a], + grid.footer(), + grid.cell(y: 4)[d], + grid.cell(y: 5)[e], + grid.cell(y: 6)[f], +) + +--- grid-footer-not-at-last-row --- +// Error: 2:3-2:19 footer must end at the last row +#grid( + grid.footer([a]), + [b], +) + +--- grid-footer-not-at-last-row-two-columns --- +// Error: 3:3-3:19 footer must end at the last row +#grid( + columns: 2, + grid.footer([a]), + [b], +) + +--- grid-footer-overlap --- +// Error: 4:3-4:19 footer would conflict with a cell placed before it at column 1 row 0 +// Hint: 4:3-4:19 try reducing that cell's rowspan or moving the footer +#grid( + columns: 2, + grid.header(), + grid.footer([a]), + grid.cell(x: 1, y: 0, rowspan: 2)[a], +) + +--- grid-footer-multiple --- +// Error: 4:3-4:19 cannot have more than one footer +#grid( + [a], + grid.footer([a]), + grid.footer([b]), +) + +--- table-footer-in-grid --- +// Error: 3:3-3:20 cannot use `table.footer` as a grid footer; use `grid.footer` instead +#grid( + [a], + table.footer([a]), +) + +--- grid-footer-in-table --- +// Error: 3:3-3:19 cannot use `grid.footer` as a table footer; use `table.footer` instead +#table( + [a], + grid.footer([a]), +) + +--- grid-footer-in-grid-header --- +// Error: 14-28 cannot place a grid footer within another footer or header +#grid.header(grid.footer[a]) + +--- table-footer-in-grid-header --- +// Error: 14-29 cannot place a table footer within another footer or header +#grid.header(table.footer[a]) + +--- grid-footer-in-table-header --- +// Error: 15-29 cannot place a grid footer within another footer or header +#table.header(grid.footer[a]) + +--- table-footer-in-table-header --- +// Error: 15-30 cannot place a table footer within another footer or header +#table.header(table.footer[a]) + +--- grid-footer-in-grid-footer --- +// Error: 14-28 cannot place a grid footer within another footer or header +#grid.footer(grid.footer[a]) + +--- table-footer-in-grid-footer --- +// Error: 14-29 cannot place a table footer within another footer or header +#grid.footer(table.footer[a]) + +--- grid-footer-in-table-footer --- +// Error: 15-29 cannot place a grid footer within another footer or header +#table.footer(grid.footer[a]) + +--- table-footer-in-table-footer --- +// Error: 15-30 cannot place a table footer within another footer or header +#table.footer(table.footer[a]) + +--- grid-header-in-grid-footer --- +// Error: 14-28 cannot place a grid header within another header or footer +#grid.footer(grid.header[a]) + +--- table-header-in-grid-footer --- +// Error: 14-29 cannot place a table header within another header or footer +#grid.footer(table.header[a]) + +--- grid-header-in-table-footer --- +// Error: 15-29 cannot place a grid header within another header or footer +#table.footer(grid.header[a]) + +--- table-header-in-table-footer --- +// Error: 15-30 cannot place a table header within another header or footer +#table.footer(table.header[a]) + +--- grid-header-footer-block-with-fixed-height --- +#set page(height: 17em) +#table( + rows: (auto, 2.5em, auto), + table.header[*Hello*][*World*], + block(width: 2em, height: 10em, fill: red), + table.footer[*Bye*][*World*], +) + +--- grid-header-footer-and-rowspan-non-contiguous-1 --- +// Rowspan sizing algorithm doesn't do the best job at non-contiguous content +// ATM. +#set page(height: 20em) + +#table( + rows: (auto, 2.5em, 2em, auto, 5em, 2em, 2.5em), + table.header[*Hello*][*World*], + table.cell(rowspan: 3, lorem(20)), + table.footer[*Ok*][*Bye*], +) + +--- grid-header-footer-and-rowspan-non-contiguous-2 --- +// This should look right +#set page(height: 20em) + +#table( + rows: (auto, 2.5em, 2em, auto), + gutter: 3pt, + table.header[*Hello*][*World*], + table.cell(rowspan: 3, lorem(20)), + table.footer[*Ok*][*Bye*], +) +--- grid-header-and-footer-lack-of-space --- +// Test lack of space for header + text. +#set page(height: 9em + 2.5em + 1.5em) + +#table( + rows: (auto, 2.5em, auto, auto, 10em, 2.5em, auto), + gutter: 3pt, + table.header[*Hello*][*World*], + table.cell(rowspan: 3, lorem(30)), + table.footer[*Ok*][*Bye*], +) + +--- grid-header-and-footer-orphan-prevention --- +// Orphan header prevention test +#set page(height: 13em) +#v(8em) +#grid( + columns: 3, + gutter: 5pt, + grid.header( + [*Mui*], [*A*], grid.cell(rowspan: 2, fill: orange)[*B*], + [*Header*], [*Header* #v(0.1em)], + ), + ..([Test], [Test], [Test]) * 7, + grid.footer( + [*Mui*], [*A*], grid.cell(rowspan: 2, fill: orange)[*B*], + [*Footer*], [*Footer* #v(0.1em)], + ), +) + +--- grid-header-and-footer-empty --- +// Empty footer should just be a repeated blank row +#set page(height: 8em) +#table( + columns: 4, + align: center + horizon, + table.header(), + ..range(0, 2).map(i => ( + [John \##i], + table.cell(stroke: green)[123], + table.cell(stroke: blue)[456], + [789] + )).flatten(), + table.footer(), +) + +--- grid-header-and-footer-containing-rowspan --- +// When a footer has a rowspan with an empty row, it should be displayed +// properly +#set page(height: 14em, width: auto) + +#let count = counter("g") +#table( + rows: (auto, 2em, auto, auto), + table.header( + [eeec], + table.cell(rowspan: 2, count.step() + count.display()), + ), + [d], + block(width: 5em, fill: yellow, lorem(7)), + [d], + table.footer( + [eeec], + table.cell(rowspan: 2, count.step() + count.display()), + ) +) +#count.display() + +--- grid-nested-with-footers --- +// Nested table with footer should repeat both footers +#set page(height: 10em, width: auto) +#table( + table( + [a\ b\ c\ d], + table.footer[b], + ), + table.footer[a], +) + +--- grid-nested-footers --- +#set page(height: 12em, width: auto) +#table( + [a\ b\ c\ d], + table.footer(table( + [c], + [d], + table.footer[b], + )) +) + +--- grid-footer-rowspan --- +// General footer-only tests +#set page(height: 9em) +#table( + columns: 2, + [a], [], + [b], [], + [c], [], + [d], [], + [e], [], + table.footer( + [*Ok*], table.cell(rowspan: 2)[test], + [*Thanks*] + ) +) + +--- grid-footer-bare-1 --- +#set page(height: 5em) +#table( + table.footer[a][b][c] +) + +--- grid-footer-bare-2 --- +#table(table.footer[a][b][c]) + +#table( + gutter: 3pt, + table.footer[a][b][c] +) + +--- grid-footer-stroke-edge-cases --- +// Test footer stroke priority edge case +#set page(height: 10em) +#table( + columns: 2, + stroke: black, + ..(table.cell(stroke: aqua)[d],) * 8, + table.footer( + table.cell(rowspan: 2, colspan: 2)[a], + [c], [d] + ) +) + +--- grid-footer-hline-and-vline-1 --- +// Footer should appear at the bottom. Red line should be above the footer. +// Green line should be on the left border. +#set page(margin: 2pt) +#set text(6pt) +#table( + columns: 2, + inset: 1.5pt, + table.cell(y: 0)[a], + table.cell(x: 1, y: 1)[a], + table.cell(y: 2)[a], + table.footer( + table.hline(stroke: red), + table.vline(stroke: green), + [b], + ), + table.cell(x: 1, y: 3)[c] +) + +--- grid-footer-hline-and-vline-2 --- +// Table should be just one row. [c] appears at the third column. +#set page(margin: 2pt) +#set text(6pt) +#table( + columns: 3, + inset: 1.5pt, + table.cell(y: 0)[a], + table.footer( + table.hline(stroke: red), + table.hline(y: 1, stroke: aqua), + table.cell(y: 0)[b], + [c] + ) +) + +--- grid-footer-below-rowspans --- +// Footer should go below the rowspans. +#set page(margin: 2pt) +#set text(6pt) +#table( + columns: 2, + inset: 1.5pt, + table.cell(rowspan: 2)[a], table.cell(rowspan: 2)[b], + table.footer() +) diff --git a/tests/suite/layout/grid/grid.typ b/tests/suite/layout/grid/grid.typ new file mode 100644 index 00000000..f4f0b90a --- /dev/null +++ b/tests/suite/layout/grid/grid.typ @@ -0,0 +1,276 @@ +// Test grid layouts. + +--- grid-columns-sizings-rect --- +#let cell(width, color) = rect(width: width, height: 2cm, fill: color) +#set page(width: 100pt, height: 140pt) +#grid( + columns: (auto, 1fr, 3fr, 0.25cm, 3%, 2mm + 10%), + cell(0.5cm, rgb("2a631a")), + cell(100%, forest), + cell(100%, conifer), + cell(100%, rgb("ff0000")), + cell(100%, rgb("00ff00")), + cell(80%, rgb("00faf0")), + cell(1cm, rgb("00ff00")), + cell(0.5cm, rgb("2a631a")), + cell(100%, forest), + cell(100%, conifer), + cell(100%, rgb("ff0000")), + cell(100%, rgb("00ff00")), +) + +--- grid-gutter-fr --- +#set rect(inset: 0pt) +#grid( + columns: (auto, auto, 40%), + column-gutter: 1fr, + row-gutter: 1fr, + rect(fill: eastern)[dddaa aaa aaa], + rect(fill: conifer)[ccc], + rect(fill: rgb("dddddd"))[aaa], +) + +--- grid-row-sizing-manual-align --- +#set page(height: 3cm, margin: 0pt) +#grid( + columns: (1fr,), + rows: (1fr, auto, 2fr), + [], + align(center)[A bit more to the top], + [], +) + +--- grid-finance --- +// Test using the `grid` function to create a finance table. +#set page(width: 11cm, height: 2.5cm) +#grid( + columns: 5, + column-gutter: (2fr, 1fr, 1fr), + row-gutter: 6pt, + [*Quarter*], + [Expenditure], + [External Revenue], + [Financial ROI], + [_total_], + [*Q1*], + [173,472.57 \$], + [472,860.91 \$], + [51,286.84 \$], + [_350,675.18 \$_], + [*Q2*], + [93,382.12 \$], + [439,382.85 \$], + [-1,134.30 \$], + [_344,866.43 \$_], + [*Q3*], + [96,421.49 \$], + [238,583.54 \$], + [3,497.12 \$], + [_145,659.17 \$_], +) +// Test grid cells that overflow to the next region. + +--- grid-cell-breaking --- +#set page(width: 5cm, height: 3cm) +#grid( + columns: 2, + row-gutter: 8pt, + [Lorem ipsum dolor sit amet. + + Aenean commodo ligula eget dolor. Aenean massa. Penatibus et magnis.], + [Text that is rather short], + [Fireflies], + [Critical], + [Decorum], + [Rampage], +) + +--- grid-consecutive-rows-breaking --- +// Test a column that starts overflowing right after another row/column did +// that. +#set page(width: 5cm, height: 2cm) +#grid( + columns: 4 * (1fr,), + row-gutter: 10pt, + column-gutter: (0pt, 10%), + align(top, image("/assets/images/rhino.png")), + align(top, rect(inset: 0pt, fill: eastern, align(right)[LoL])), + [rofl], + [\ A] * 3, + [Ha!\ ] * 3, +) + +--- grid-same-row-multiple-columns-breaking --- +// Test two columns in the same row overflowing by a different amount. +#set page(width: 5cm, height: 2cm) +#grid( + columns: 3 * (1fr,), + row-gutter: 8pt, + column-gutter: (0pt, 10%), + [A], [B], [C], + [Ha!\ ] * 6, + [rofl], + [\ A] * 3, + [hello], + [darkness], + [my old] +) + +--- grid-nested-breaking --- +// Test grid within a grid, overflowing. +#set page(width: 5cm, height: 2.25cm) +#grid( + columns: 4 * (1fr,), + row-gutter: 10pt, + column-gutter: (0pt, 10%), + [A], [B], [C], [D], + grid(columns: 2, [A], [B], [C\ ]*3, [D]), + align(top, rect(inset: 0pt, fill: eastern, align(right)[LoL])), + [rofl], + [E\ ]*4, +) + +--- grid-column-sizing-auto-base --- +// Test that auto and relative columns use the correct base. +#grid( + columns: (auto, 60%), + rows: (auto, auto), + rect(width: 50%, height: 0.5cm, fill: conifer), + rect(width: 100%, height: 0.5cm, fill: eastern), + rect(width: 50%, height: 0.5cm, fill: forest), +) + +--- grid-column-sizing-fr-base --- +// Test that fr columns use the correct base. +#grid( + columns: (1fr,) * 4, + rows: (1cm,), + rect(width: 50%, fill: conifer), + rect(width: 50%, fill: forest), + rect(width: 50%, fill: conifer), + rect(width: 50%, fill: forest), +) + +--- grid-column-sizing-mixed-base --- +// Test that all three kinds of rows use the correct bases. +#set page(height: 4cm, margin: 0cm) +#grid( + rows: (1cm, 1fr, 1fr, auto), + rect(height: 50%, width: 100%, fill: conifer), + rect(height: 50%, width: 100%, fill: forest), + rect(height: 50%, width: 100%, fill: conifer), + rect(height: 25%, width: 100%, fill: forest), +) + +--- grid-trailing-linebreak-region-overflow --- +// Test that trailing linebreak doesn't overflow the region. +#set page(height: 2cm) +#grid[ + Hello \ + Hello \ + Hello \ + + World +] + +--- grid-breaking-expand-vertically --- +// Test that broken cell expands vertically. +#set page(height: 2.25cm) +#grid( + columns: 2, + gutter: 10pt, + align(bottom)[A], + [ + Top + #align(bottom)[ + Bottom \ + Bottom \ + #v(0pt) + Top + ] + ], + align(top)[B], +) + +--- grid-complete-rows --- +// Ensure grids expand enough for the given rows. +#grid( + columns: (2em, 2em), + rows: (2em,) * 4, + fill: red, + stroke: aqua, + [a] +) + +--- grid-auto-shrink --- +// Test iterative auto column shrinking. +#set page(width: 210mm - 2 * 2.5cm + 2 * 10pt) +#set text(11pt) +#table( + columns: 4, + [Hello!], + [Hello there, my friend!], + [Hello there, my friends! Hi!], + [Hello there, my friends! Hi! What is going on right now?], +) + +--- issue-grid-base-auto-row --- +// Test that grid base for auto rows makes sense. +#set page(height: 150pt) +#table( + columns: (1.5cm, auto), + rows: (auto, auto), + rect(width: 100%, fill: red), + rect(width: 100%, fill: blue), + rect(width: 100%, height: 50%, fill: green), +) + +--- issue-grid-base-auto-row-list --- +#rect(width: 100%, height: 1em) +- #rect(width: 100%, height: 1em) + - #rect(width: 100%, height: 1em) + +--- issue-grid-skip --- +// Grid now skips a remaining region when one of the cells +// doesn't fit into it at all. +#set page(height: 100pt) +#grid( + columns: (2cm, auto), + rows: (auto, auto), + rect(width: 100%, fill: red), + rect(width: 100%, fill: blue), + rect(width: 100%, height: 80%, fill: green), + [hello \ darkness #parbreak() my \ old \ friend \ I], + rect(width: 100%, height: 20%, fill: blue), + polygon(fill: red, (0%, 0%), (100%, 0%), (100%, 20%)) +) + +--- issue-grid-skip-list --- +#set page(height: 60pt) +#lorem(5) +- #lorem(5) + +--- issue-grid-double-skip --- +// Ensure that the list does not jump to the third page. +#set page(height: 70pt) +#v(40pt) +The following: ++ A ++ B + +--- issue-grid-gutter-skip --- +// Ensure gutter rows at the top or bottom of a region are skipped. +#set page(height: 10em) + +#table( + row-gutter: 1.5em, + inset: 0pt, + rows: (1fr, auto), + [a], + [], + [], + [f], + [e\ e], + [], + [a] +) diff --git a/tests/suite/layout/grid/headers.typ b/tests/suite/layout/grid/headers.typ new file mode 100644 index 00000000..b9a90461 --- /dev/null +++ b/tests/suite/layout/grid/headers.typ @@ -0,0 +1,368 @@ +--- grid-headers --- +#set page(width: auto, height: 12em) +#table( + columns: 5, + align: center + horizon, + table.header( + table.cell(colspan: 5)[*Cool Zone*], + table.cell(stroke: red)[*Name*], table.cell(stroke: aqua)[*Number*], [*Data 1*], [*Data 2*], [*Etc*], + table.hline(start: 2, end: 3, stroke: yellow) + ), + ..range(0, 6).map(i => ([John \##i], table.cell(stroke: green)[123], table.cell(stroke: blue)[456], [789], [?], table.hline(start: 4, end: 5, stroke: red))).flatten() +) + +--- grid-headers-no-repeat --- +// Disable repetition +#set page(width: auto, height: 12em) +#table( + columns: 5, + align: center + horizon, + table.header( + table.cell(colspan: 5)[*Cool Zone*], + table.cell(stroke: red)[*Name*], table.cell(stroke: aqua)[*Number*], [*Data 1*], [*Data 2*], [*Etc*], + table.hline(start: 2, end: 3, stroke: yellow), + repeat: false + ), + ..range(0, 6).map(i => ([John \##i], table.cell(stroke: green)[123], table.cell(stroke: blue)[456], [789], [?], table.hline(start: 4, end: 5, stroke: red))).flatten() +) + +--- grid-headers-gutter --- +#set page(width: auto, height: 12em) +#table( + columns: 5, + align: center + horizon, + gutter: 3pt, + table.header( + table.cell(colspan: 5)[*Cool Zone*], + table.cell(stroke: red)[*Name*], table.cell(stroke: aqua)[*Number*], [*Data 1*], [*Data 2*], [*Etc*], + table.hline(start: 2, end: 3, stroke: yellow), + ), + ..range(0, 6).map(i => ([John \##i], table.cell(stroke: green)[123], table.cell(stroke: blue)[456], [789], [?], table.hline(start: 4, end: 5, stroke: red))).flatten() +) + +--- grid-header-relative-row-sizes --- +// Relative lengths +#set page(height: 10em) +#table( + rows: (30%, 30%, auto), + table.header( + [*A*], + [*B*] + ), + [C], + [C] +) + +--- grid-header-cell-with-y --- +#grid( + grid.cell(y: 1)[a], + grid.header(grid.cell(y: 0)[b]), + grid.cell(y: 2)[c] +) + +--- grid-header-last-child --- +// When the header is the last grid child, it shouldn't include the gutter row +// after it, because there is none. +#grid( + columns: 2, + gutter: 3pt, + grid.header( + [a], [b], + [c], [d] + ) +) + +--- grid-header-nested --- +#set page(height: 14em) +#let t(n) = table( + columns: 3, + align: center + horizon, + gutter: 3pt, + table.header( + table.cell(colspan: 3)[*Cool Zone #n*], + [*Name*], [*Num*], [*Data*] + ), + ..range(0, 5).map(i => ([\##i], table.cell(stroke: green)[123], table.cell(stroke: blue)[456])).flatten() +) +#grid( + gutter: 3pt, + t(0), + t(1) +) + +--- grid-header-hline-and-vline --- +// Test line positioning in header +#table( + columns: 3, + stroke: none, + table.hline(stroke: red, end: 2), + table.vline(stroke: red, end: 3), + table.header( + table.hline(stroke: aqua, start: 2), + table.vline(stroke: aqua, start: 3), [*A*], table.hline(stroke: orange), table.vline(stroke: orange), [*B*], + [*C*], [*D*] + ), + [a], [b], + [c], [d], + [e], [f] +) + +--- grid-header-not-at-first-row --- +// Error: 3:3-3:19 header must start at the first row +// Hint: 3:3-3:19 remove any rows before the header +#grid( + [a], + grid.header([b]) +) + +--- grid-header-not-at-first-row-two-columns --- +// Error: 4:3-4:19 header must start at the first row +// Hint: 4:3-4:19 remove any rows before the header +#grid( + columns: 2, + [a], + grid.header([b]) +) + +--- grow-header-multiple --- +// Error: 3:3-3:19 cannot have more than one header +#grid( + grid.header([a]), + grid.header([b]), + [a], +) + +--- table-header-in-grid --- +// Error: 2:3-2:20 cannot use `table.header` as a grid header; use `grid.header` instead +#grid( + table.header([a]), + [a], +) + +--- grid-header-in-table --- +// Error: 2:3-2:19 cannot use `grid.header` as a table header; use `table.header` instead +#table( + grid.header([a]), + [a], +) + +--- grid-header-in-grid-header --- +// Error: 14-28 cannot place a grid header within another header or footer +#grid.header(grid.header[a]) + +--- table-header-in-grid-header --- +// Error: 14-29 cannot place a table header within another header or footer +#grid.header(table.header[a]) + +--- grid-header-in-table-header --- +// Error: 15-29 cannot place a grid header within another header or footer +#table.header(grid.header[a]) + +--- table-header-in-table-header --- +// Error: 15-30 cannot place a table header within another header or footer +#table.header(table.header[a]) + +--- grid-header-block-with-fixed-height --- +#set page(height: 15em) +#table( + rows: (auto, 2.5em, auto), + table.header( + [*Hello*], + [*World*] + ), + block(width: 2em, height: 20em, fill: red) +) + +--- grid-header-and-rowspan-non-contiguous-1 --- +// Rowspan sizing algorithm doesn't do the best job at non-contiguous content +// ATM. +#set page(height: 15em) + +#table( + rows: (auto, 2.5em, 2em, auto, 5em), + table.header( + [*Hello*], + [*World*] + ), + table.cell(rowspan: 3, lorem(40)) +) + +--- grid-header-and-rowspan-non-contiguous-2 --- +// Rowspan sizing algorithm doesn't do the best job at non-contiguous content +// ATM. +#set page(height: 15em) + +#table( + rows: (auto, 2.5em, 2em, auto, 5em), + gutter: 3pt, + table.header( + [*Hello*], + [*World*] + ), + table.cell(rowspan: 3, lorem(40)) +) + +--- grid-header-and-rowspan-non-contiguous-3 --- +// This should look right +#set page(height: 15em) + +#table( + rows: (auto, 2.5em, 2em, auto), + gutter: 3pt, + table.header( + [*Hello*], + [*World*] + ), + table.cell(rowspan: 3, lorem(40)) +) + +--- grid-header-lack-of-space --- +// Test lack of space for header + text. +#set page(height: 9em) + +#table( + rows: (auto, 2.5em, auto, auto, 10em), + gutter: 3pt, + table.header( + [*Hello*], + [*World*] + ), + table.cell(rowspan: 3, lorem(80)) +) + +--- grid-header-orphan-prevention --- +// Orphan header prevention test +#set page(height: 12em) +#v(8em) +#grid( + columns: 3, + grid.header( + [*Mui*], [*A*], grid.cell(rowspan: 2, fill: orange)[*B*], + [*Header*], [*Header* #v(0.1em)] + ), + ..([Test], [Test], [Test]) * 20 +) + +--- grid-header-empty --- +// Empty header should just be a repeated blank row +#set page(height: 12em) +#table( + columns: 4, + align: center + horizon, + table.header(), + ..range(0, 4).map(i => ([John \##i], table.cell(stroke: green)[123], table.cell(stroke: blue)[456], [789])).flatten() +) + +--- grid-header-containing-rowspan --- +// When a header has a rowspan with an empty row, it should be displayed +// properly +#set page(height: 10em) + +#let count = counter("g") +#table( + rows: (auto, 2em, auto, auto), + table.header( + [eeec], + table.cell(rowspan: 2, count.step() + count.display()), + ), + [d], + block(width: 5em, fill: yellow, lorem(15)), + [d] +) +#count.display() + +--- grid-header-expand --- +// Ensure header expands to fit cell placed in it after its declaration +#set page(height: 10em) +#table( + columns: 2, + table.header( + [a], [b], + [c], + ), + table.cell(x: 1, y: 1, rowspan: 2, lorem(80)) +) + +--- grid-nested-with-headers --- +// Nested table with header should repeat both headers +#set page(height: 10em) +#table( + table.header( + [a] + ), + table( + table.header( + [b] + ), + [a\ b\ c\ d] + ) +) + +--- grid-nested-headers --- +#set page(height: 12em) +#table( + table.header( + table( + table.header( + [b] + ), + [c], + [d] + ) + ), + [a\ b] +) + +--- grid-header-stroke-edge-cases --- +// Test header stroke priority edge case (last header row removed) +#set page(height: 8em) +#table( + columns: 2, + stroke: black, + gutter: (auto, 3pt), + table.header( + [c], [d], + ), + ..(table.cell(stroke: aqua)[d],) * 8, +) + +--- grid-header-hline-bottom --- +// Yellow line should be kept here +#set text(6pt) +#table( + column-gutter: 3pt, + inset: 1pt, + table.header( + [a], + table.hline(stroke: yellow), + ), + table.cell(rowspan: 2)[b] +) + +--- grid-header-hline-bottom-manually --- +// Red line should be kept here +#set page(height: 6em) +#set text(6pt) +#table( + column-gutter: 3pt, + inset: 1pt, + table.header( + table.hline(stroke: red, position: bottom), + [a], + ), + [a], + table.cell(stroke: aqua)[b] +) + +--- grid-header-rowspan-base --- +#set page(height: 7em) +#set text(6pt) +#let full-block = block(width: 2em, height: 100%, fill: red) +#table( + columns: 3, + inset: 1.5pt, + table.header( + [a], full-block, table.cell(rowspan: 2, full-block), + [b] + ) +) diff --git a/tests/suite/layout/grid/positioning.typ b/tests/suite/layout/grid/positioning.typ new file mode 100644 index 00000000..31896d99 --- /dev/null +++ b/tests/suite/layout/grid/positioning.typ @@ -0,0 +1,203 @@ +// Test cell positioning in grids. + +--- grid-cell-show-x-y --- +#{ + show grid.cell: it => (it.x, it.y) + grid( + columns: 2, + inset: 5pt, + fill: aqua, + gutter: 3pt, + [Hello], [World], + [Sweet], [Home] + ) +} +#{ + show table.cell: it => pad(rest: it.inset)[#(it.x, it.y)] + table( + columns: 2, + gutter: 3pt, + [Hello], [World], + [Sweet], [Home] + ) +} + +--- grid-cell-position-out-of-order --- +// Positioning cells in a different order than they appear +#grid( + columns: 2, + [A], [B], + grid.cell(x: 1, y: 2)[C], grid.cell(x: 0, y: 2)[D], + grid.cell(x: 1, y: 1)[E], grid.cell(x: 0, y: 1)[F], +) + +--- grid-cell-position-extra-rows --- +// Creating more rows by positioning out of bounds +#grid( + columns: 3, + rows: 1.5em, + inset: 5pt, + fill: (x, y) => if (x, y) == (0, 0) { blue } else if (x, y) == (2, 3) { red } else { green }, + [A], + grid.cell(x: 2, y: 3)[B] +) + +#table( + columns: (3em, 1em, 3em), + rows: 1.5em, + inset: (top: 0pt, bottom: 0pt, rest: 5pt), + fill: (x, y) => if (x, y) == (0, 0) { blue } else if (x, y) == (2, 3) { red } else { green }, + align: (x, y) => (left, center, right).at(x), + [A], + table.cell(x: 2, y: 3)[B] +) + +--- grid-cell-position-collide --- +// Error: 3:3-3:42 attempted to place a second cell at column 0, row 0 +// Hint: 3:3-3:42 try specifying your cells in a different order +#grid( + [A], + grid.cell(x: 0, y: 0)[This shall error] +) + +--- table-cell-position-collide --- +// Error: 3:3-3:43 attempted to place a second cell at column 0, row 0 +// Hint: 3:3-3:43 try specifying your cells in a different order +#table( + [A], + table.cell(x: 0, y: 0)[This shall error] +) + +--- grid-cell-position-automatic-skip-manual --- +// Automatic position cell skips custom position cell +#grid( + grid.cell(x: 0, y: 0)[This shall not error], + [A] +) + +--- grid-cell-position-x-out-of-bounds --- +// Error: 4:3-4:36 cell could not be placed at invalid column 2 +#grid( + columns: 2, + [A], + grid.cell(x: 2)[This shall error] +) + +--- grid-cell-position-partial --- +// Partial positioning +#grid( + columns: 3, + rows: 1.5em, + inset: 5pt, + fill: aqua, + [A], grid.cell(y: 1, fill: green)[B], [C], grid.cell(x: auto, y: 1, fill: green)[D], [E], + grid.cell(y: 2, fill: green)[F], grid.cell(x: 0, fill: orange)[G], grid.cell(x: 0, y: auto, fill: orange)[H], + grid.cell(x: 1, fill: orange)[I] +) + +#table( + columns: 3, + rows: 1.5em, + inset: 5pt, + fill: aqua, + [A], table.cell(y: 1, fill: green)[B], [C], table.cell(x: auto, y: 1, fill: green)[D], [E], + table.cell(y: 2, fill: green)[F], table.cell(x: 0, fill: orange)[G], table.cell(x: 0, y: auto, fill: orange)[H], + table.cell(x: 1, fill: orange)[I] +) + +--- grid-cell-position-partial-collide --- +// Error: 4:3-4:21 cell could not be placed in row 0 because it was full +// Hint: 4:3-4:21 try specifying your cells in a different order +#grid( + columns: 2, + [A], [B], + grid.cell(y: 0)[C] +) + +--- table-cell-position-partial-collide --- +// Error: 4:3-4:22 cell could not be placed in row 0 because it was full +// Hint: 4:3-4:22 try specifying your cells in a different order +#table( + columns: 2, + [A], [B], + table.cell(y: 0)[C] +) + +--- grid-calendar --- +#set page(width: auto) +#show grid.cell: it => { + if it.y == 0 { + set text(white) + strong(it) + } else { + // For the second row and beyond, we will write the day number for each + // cell. + + // In general, a cell's index is given by cell.x + columns * cell.y. + // Days start in the second grid row, so we subtract 1 row. + // But the first day is day 1, not day 0, so we add 1. + let day = it.x + 7 * (it.y - 1) + 1 + if day <= 31 { + // Place the day's number at the top left of the cell. + // Only if the day is valid for this month (not 32 or higher). + place(top + left, dx: 2pt, dy: 2pt, text(8pt, red.darken(40%))[#day]) + } + it + } +} + +#grid( + fill: (x, y) => if y == 0 { gray.darken(50%) }, + columns: (30pt,) * 7, + rows: (auto, 30pt), + // Events will be written at the bottom of each day square. + align: bottom, + inset: 5pt, + stroke: (thickness: 0.5pt, dash: "densely-dotted"), + + [Sun], [Mon], [Tue], [Wed], [Thu], [Fri], [Sat], + + // This event will occur on the first Friday (sixth column). + grid.cell(x: 5, fill: yellow.darken(10%))[Call], + + // This event will occur every Monday (second column). + // We have to repeat it 5 times so it occurs every week. + ..(grid.cell(x: 1, fill: red.lighten(50%))[Meet],) * 5, + + // This event will occur at day 19. + grid.cell(x: 4, y: 3, fill: orange.lighten(25%))[Talk], + + // These events will occur at the second week, where available. + grid.cell(y: 2, fill: aqua)[Chat], + grid.cell(y: 2, fill: aqua)[Walk], +) + +--- grid-exam --- +#set page(width: auto) +#show table.cell: it => { + if it.x == 0 or it.y == 0 { + set text(white) + strong(it) + } else if it.body == [] { + // Replace empty cells with 'N/A' + pad(rest: it.inset)[_N/A_] + } else { + it + } +} + +#table( + fill: (x, y) => if x == 0 or y == 0 { gray.darken(50%) }, + columns: 4, + [], [Exam 1], [Exam 2], [Exam 3], + ..([John], [Mary], [Jake], [Robert]).map(table.cell.with(x: 0)), + + // Mary got grade A on Exam 3. + table.cell(x: 3, y: 2, fill: green)[A], + + // Everyone got grade A on Exam 2. + ..(table.cell(x: 2, fill: green)[A],) * 4, + + // Robert got grade B on other exams. + ..(table.cell(y: 4, fill: aqua)[B],) * 2, +) diff --git a/tests/suite/layout/grid/rowspan.typ b/tests/suite/layout/grid/rowspan.typ new file mode 100644 index 00000000..f7a377b6 --- /dev/null +++ b/tests/suite/layout/grid/rowspan.typ @@ -0,0 +1,490 @@ +--- grid-rowspan --- +#grid( + columns: 4, + fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, + inset: 5pt, + align: center, + grid.cell(rowspan: 2, fill: orange)[*Left*], + [Right A], [Right A], [Right A], + [Right B], grid.cell(colspan: 2, rowspan: 2, fill: orange.darken(10%))[B Wide], + [Left A], [Left A], + [Left B], [Left B], grid.cell(colspan: 2, rowspan: 3, fill: orange)[Wide and Long] +) + +#table( + columns: 4, + fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, + inset: 5pt, + align: center, + table.cell(rowspan: 2, fill: orange)[*Left*], + [Right A], [Right A], [Right A], + [Right B], table.cell(colspan: 2, rowspan: 2, fill: orange.darken(10%))[B Wide], + [Left A], [Left A], + [Left B], [Left B], table.cell(colspan: 2, rowspan: 3, fill: orange)[Wide and Long] +) + +--- grid-rowspan-gutter --- +#grid( + columns: 4, + fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, + inset: 5pt, + align: center, + gutter: 3pt, + grid.cell(rowspan: 2, fill: orange)[*Left*], + [Right A], [Right A], [Right A], + [Right B], grid.cell(colspan: 2, rowspan: 2, fill: orange.darken(10%))[B Wide], + [Left A], [Left A], + [Left B], [Left B], grid.cell(colspan: 2, rowspan: 3, fill: orange)[Wide and Long] +) + +#table( + columns: 4, + fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, + inset: 5pt, + align: center, + gutter: 3pt, + table.cell(rowspan: 2, fill: orange)[*Left*], + [Right A], [Right A], [Right A], + [Right B], table.cell(colspan: 2, rowspan: 2, fill: orange.darken(10%))[B Wide], + [Left A], [Left A], + [Left B], [Left B], table.cell(colspan: 2, rowspan: 3, fill: orange)[Wide and Long] +) + +--- grid-rowspan-fixed-size --- +// Fixed-size rows +#set page(height: 10em) +#grid( + columns: 2, + rows: 1.5em, + fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, + grid.cell(rowspan: 3)[R1], [b], + [c], + [d], + [e], [f], + grid.cell(rowspan: 5)[R2], [h], + [i], + [j], + [k], + [l], + [m], [n] +) + +--- grid-rowspan-cell-coordinates --- +// Cell coordinate tests +#set page(height: 10em) +#show table.cell: it => [(#it.x, #it.y)] +#table( + columns: 3, + fill: red, + [a], [b], table.cell(rowspan: 2)[c], + table.cell(colspan: 2)[d], + table.cell(colspan: 3, rowspan: 10)[a], + table.cell(colspan: 2)[b], +) +#table( + columns: 3, + gutter: 3pt, + fill: red, + [a], [b], table.cell(rowspan: 2)[c], + table.cell(colspan: 2)[d], + table.cell(colspan: 3, rowspan: 9)[a], + table.cell(colspan: 2)[b], +) + +--- grid-rowspan-over-auto-row --- +// Auto row expansion +#set page(height: 10em) +#grid( + columns: (1em, 1em), + rows: (0.5em, 0.5em, auto), + fill: orange, + gutter: 3pt, + grid.cell(rowspan: 4, [x x x x] + place(bottom)[*Bot*]), + [a], + [b], + [c], + [d] +) + +--- grid-rowspan-excessive --- +// Excessive rowspan (no gutter) +#set page(height: 10em) +#table( + columns: 4, + fill: red, + [a], [b], table.cell(rowspan: 2)[c], [d], + table.cell(colspan: 2, stroke: (bottom: aqua + 2pt))[e], table.cell(stroke: (bottom: aqua))[f], + table.cell(colspan: 2, rowspan: 10)[R1], table.cell(colspan: 2, rowspan: 10)[R2], + [b], +) + +--- grid-rowspan-excessive-gutter --- +// Excessive rowspan (with gutter) +#set page(height: 10em) +#table( + columns: 4, + gutter: 3pt, + fill: red, + [a], [b], table.cell(rowspan: 2)[c], [d], + table.cell(colspan: 2, stroke: (bottom: aqua + 2pt))[e], table.cell(stroke: (bottom: aqua))[f], + table.cell(colspan: 2, rowspan: 10)[R1], table.cell(colspan: 2, rowspan: 10)[R2], + [b], +) + +--- grid-rowspan-over-fr-row-at-end --- +// Fractional rows +// They cause the auto row to expand more than needed. +#set page(height: 10em) +#grid( + fill: red, + gutter: 3pt, + columns: 3, + rows: (1em, auto, 1fr), + [a], [b], grid.cell(rowspan: 3, block(height: 4em, width: 1em, fill: orange)), + [c], [d], + [e], [f] +) + +--- grid-rowspan-over-fr-row-at-start --- +// Fractional rows +#set page(height: 10em) +#grid( + fill: red, + gutter: 3pt, + columns: 3, + rows: (1fr, auto, 1em), + [a], [b], grid.cell(rowspan: 3, block(height: 4em, width: 1em, fill: orange)), + [c], [d], + [e], [f] +) + +--- grid-rowspan-cell-order --- +// Cell order +#let count = counter("count") +#show grid.cell: it => { + count.step() + count.display() +} + +#grid( + columns: (2em,) * 3, + stroke: aqua, + rows: 1.2em, + fill: (x, y) => if calc.odd(x + y) { red } else { orange }, + [a], grid.cell(rowspan: 2)[b], grid.cell(rowspan: 2)[c], + [d], + grid.cell(rowspan: 2)[f], [g], [h], + [i], [j], + [k], [l], [m], + grid.cell(rowspan: 2)[n], [o], [p], + [q], [r], + [s], [t], [u] +) + +--- grid-rowspan-unbreakable-1 --- +#table( + columns: 3, + rows: (auto, auto, auto, 2em), + gutter: 3pt, + table.cell(rowspan: 4)[a \ b\ c\ d\ e], [c], [d], + [e], table.cell(breakable: false, rowspan: 2)[f], + [g] +) + +--- grid-rowspan-unbreakable-2 --- +// Test cell breakability +#show grid.cell: it => { + assert.eq(it.breakable, (it.x, it.y) != (0, 6) and (it.y in (2, 5, 6) or (it.x, it.y) in ((0, 1), (2, 3), (1, 7)))) + it.breakable +} +#grid( + columns: 3, + rows: (6pt, 1fr, auto, 1%, 1em, auto, auto, 0.2in), + row-gutter: (0pt, 0pt, 0pt, auto), + [a], [b], [c], + grid.cell(rowspan: 3)[d], [e], [f], + [g], [h], + [i], grid.cell(rowspan: 2)[j], + [k], + grid.cell(y: 5)[l], + grid.cell(y: 6, breakable: false)[m], grid.cell(y: 6, breakable: true)[n], + grid.cell(y: 7, breakable: false)[o], grid.cell(y: 7, breakable: true)[p], grid.cell(y: 7, breakable: auto)[q] +) + +--- grid-rowspan-in-all-columns-stroke --- +#table( + columns: 2, + table.cell(stroke: (bottom: red))[a], [b], + table.hline(stroke: green), + table.cell(stroke: (top: yellow, left: green, right: aqua, bottom: blue), colspan: 1, rowspan: 2)[d], table.cell(colspan: 1, rowspan: 2)[e], + [f], + [g] +) + +--- grid-rowspan-in-all-columns-stroke-gutter --- +#table( + columns: 2, + gutter: 3pt, + table.cell(stroke: (bottom: red))[a], [b], + table.hline(stroke: green), + table.cell(stroke: (top: yellow, left: green, right: aqua, bottom: blue), colspan: 1, rowspan: 2)[d], table.cell(colspan: 1, rowspan: 2)[e], + [f], + [g] +) + +--- grid-rowspan-block-full-height --- +// Block below shouldn't expand to the end of the page, but stay within its +// rows' boundaries. +#set page(height: 9em) +#table( + rows: (1em, 1em, 1fr, 1fr, auto), + table.cell(rowspan: 2, block(width: 2em, height: 100%, fill: red)), + table.cell(rowspan: 2, block(width: 2em, height: 100%, fill: red)), + [a] +) + +--- grid-rowspan-block-overflow --- +#set page(height: 7em) +#table( + columns: 3, + [], [], table.cell(breakable: true, rowspan: 2, block(width: 2em, height: 100%, fill: red)), + table.cell(breakable: false, block(width: 2em, height: 100%, fill: red)), + table.cell(breakable: false, rowspan: 2, block(width: 2em, height: 100%, fill: red)), +) + +// Rowspan split tests + +--- grid-rowspan-split-1 --- +#set page(height: 10em) +#table( + columns: 2, + rows: (auto, auto, 3em), + fill: red, + [a], table.cell(rowspan: 3, block(width: 50%, height: 10em, fill: orange) + place(bottom)[*ZD*]), + [e], + [f] +) + +--- grid-rowspan-split-2 --- +#set page(height: 10em) +#table( + columns: 2, + rows: (auto, auto, 3em), + row-gutter: 1em, + fill: red, + [a], table.cell(rowspan: 3, block(width: 50%, height: 10em, fill: orange) + place(bottom)[*ZD*]), + [e], + [f] +) + +--- grid-rowspan-split-3 --- +#set page(height: 5em) +#table( + columns: 2, + fill: red, + inset: 0pt, + table.cell(fill: orange, rowspan: 10, place(bottom)[*Z*] + [x\ ] * 10 + place(bottom)[*ZZ*]), + ..([y],) * 10, + [a], [b], +) + +--- grid-rowspan-split-4 --- +#set page(height: 5em) +#table( + columns: 2, + fill: red, + inset: 0pt, + gutter: 2pt, + table.cell(fill: orange, rowspan: 10, place(bottom)[*Z*] + [x\ ] * 10 + place(bottom)[*ZZ*]), + ..([y],) * 10, + [a], [b], +) + +--- grid-rowspan-split-5 --- +#set page(height: 5em) +#table( + columns: 2, + fill: red, + inset: 0pt, + table.cell(fill: orange, rowspan: 10, breakable: false, place(bottom)[*Z*] + [x\ ] * 10 + place(bottom)[*ZZ*]), + ..([y],) * 10, + [a], [b], +) + +--- grid-rowspan-split-6 --- +#set page(height: 5em) +#table( + columns: 2, + fill: red, + inset: 0pt, + gutter: 2pt, + table.cell(fill: orange, rowspan: 10, breakable: false, place(bottom)[*Z*] + [x\ ] * 10 + place(bottom)[*ZZ*]), + ..([y],) * 10, + [a], [b], +) + +--- grid-rowspan-split-7 --- +#set page(height: 5em) +#grid( + columns: 2, + stroke: red, + inset: 5pt, + grid.cell(rowspan: 5)[a\ b\ c\ d\ e] +) + +--- grid-rowspan-split-8 --- +#set page(height: 5em) +#table( + columns: 2, + gutter: 3pt, + stroke: red, + inset: 5pt, + table.cell(rowspan: 5)[a\ b\ c\ d\ e] +) + +// Rowspan split without ending at the auto row + +--- grid-rowspan-split-9 --- +#set page(height: 6em) +#table( + rows: (4em,) * 7 + (auto,) + (4em,) * 7, + columns: 2, + column-gutter: 1em, + row-gutter: (1em, 2em) * 4, + fill: (x, y) => if calc.odd(x + y) { orange.lighten(20%) } else { red }, + table.cell(rowspan: 15, [a \ ] * 15), + [] * 15 +) + +--- grid-rowspan-split-10 --- +#set page(height: 6em) +#table( + rows: (4em,) * 7 + (auto,) + (4em,) * 7, + columns: 2, + column-gutter: 1em, + row-gutter: (1em, 2em) * 4, + fill: (x, y) => if calc.odd(x + y) { green } else { green.darken(40%) }, + table.cell(rowspan: 15, block(fill: blue, width: 2em, height: 4em * 14 + 3em)), + [] * 15 +) + +--- grid-rowspan-split-11 --- +#set page(height: 6em) +#table( + rows: (3em,) * 15, + columns: 2, + column-gutter: 1em, + row-gutter: (1em, 2em) * 4, + fill: (x, y) => if calc.odd(x + y) { aqua } else { blue }, + table.cell(breakable: true, rowspan: 15, [a \ ] * 15), + [] * 15 +) + +// Some splitting corner cases + +--- grid-rowspan-split-12 --- +// Inside the larger rowspan's range, there's an unbreakable rowspan and a +// breakable rowspan. This should work normally. +// The auto row will also expand ignoring the last fractional row. +#set page(height: 10em) +#table( + gutter: 0.5em, + columns: 2, + rows: (2em,) * 10 + (auto, auto, 2em, 1fr), + fill: (_, y) => if calc.even(y) { aqua } else { blue }, + table.cell(rowspan: 14, block(width: 2em, height: 2em * 10 + 2em + 5em, fill: red)[]), + ..([a],) * 5, + table.cell(rowspan: 3)[a\ b], + table.cell(rowspan: 5, [a\ b\ c\ d\ e\ f\ g\ h]), + [z] +) + +--- grid-rowspan-split-13 --- +// Inset moving to next region bug +#set page(width: 10cm, height: 2.5cm, margin: 0.5cm) +#set text(size: 11pt) +#table( + columns: (1fr, 1fr, 1fr), + [A], + [B], + [C], + [D], + table.cell(rowspan: 2, lorem(4)), + [E], + [F], + [G], +) + +--- grid-rowspan-split-14 --- +// Second lorem must be sent to the next page, too big +#set page(width: 10cm, height: 9cm, margin: 1cm) +#set text(size: 11pt) +#table( + columns: (1fr, 1fr, 1fr), + align: center, + rows: (4cm, auto), + [A], [B], [C], + table.cell(rowspan: 4, breakable: false, lorem(10)), + [D], + table.cell(rowspan: 2, breakable: false, lorem(20)), + [E], +) + +--- grid-rowspan-split-15 --- +// Auto row must expand properly in both cases +#set text(10pt) +#show table.cell: it => if it.x == 0 { it } else { layout(size => size.height) } +#table( + columns: 2, + rows: (1em, auto, 2em, 3em, 4em), + gutter: 3pt, + table.cell(rowspan: 5, block(fill: orange, height: 15em)[a]), + [b], + [c], + [d], + [e], + [f] +) + +#table( + columns: 2, + rows: (1em, auto, 2em, 3em, 4em), + gutter: 3pt, + table.cell(rowspan: 5, breakable: false, block(fill: orange, height: 15em)[a]), + [b], + [c], + [d], + [e], + [f] +) + +--- grid-rowspan-split-16 --- +// Expanding on unbreakable auto row +#set page(height: 7em, margin: (bottom: 2em)) +#grid( + columns: 2, + rows: (1em, 1em, auto, 1em, 1em, 1em), + fill: (x, y) => if x == 0 { aqua } else { blue }, + stroke: black, + gutter: 2pt, + grid.cell(rowspan: 5, block(height: 10em)[a]), + [a], + [b], + grid.cell(breakable: false, v(3em) + [c]), + [d], + [e], + [f], [g] +) + +--- grid-rowspan-split-17 --- +#show table.cell.where(x: 0): strong +#show table.cell.where(y: 0): strong +#set page(height: 13em) +#let lets-repeat(thing, n) = ((thing + colbreak(),) * (calc.max(0, n - 1)) + (thing,)).join() +#table( + columns: 4, + fill: (x, y) => if x == 0 or y == 0 { gray }, + [], [Test 1], [Test 2], [Test 3], + table.cell(rowspan: 15, align: horizon, lets-repeat((rotate(-90deg, reflow: true)[*All Tests*]), 3)), + ..([123], [456], [789]) * 15 +) diff --git a/tests/suite/layout/grid/rtl.typ b/tests/suite/layout/grid/rtl.typ new file mode 100644 index 00000000..7c0e999a --- /dev/null +++ b/tests/suite/layout/grid/rtl.typ @@ -0,0 +1,195 @@ +// Test RTL grid. + +--- list-rtl --- +#set text(dir: rtl) +- מימין לשמאל + +--- grid-rtl --- +#set text(dir: rtl) +#table(columns: 2)[A][B][C][D] + +--- grid-rtl-colspan --- +// Test interaction between RTL and colspans +#set text(dir: rtl) +#grid( + columns: 4, + fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, + inset: 5pt, + align: center, + grid.cell(colspan: 4)[*Full Header*], + grid.cell(colspan: 2, fill: orange)[*Half*], + grid.cell(colspan: 2, fill: orange.darken(10%))[*Half*], + [*A*], [*B*], [*C*], [*D*], + [1], [2], [3], [4], + [5], grid.cell(colspan: 3, fill: orange.darken(10%))[6], + grid.cell(colspan: 2, fill: orange)[7], [8], [9], + [10], grid.cell(colspan: 2, fill: orange.darken(10%))[11], [12] +) + +#grid( + columns: 4, + fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, + inset: 5pt, + align: center, + gutter: 3pt, + grid.cell(colspan: 4)[*Full Header*], + grid.cell(colspan: 2, fill: orange)[*Half*], + grid.cell(colspan: 2, fill: orange.darken(10%))[*Half*], + [*A*], [*B*], [*C*], [*D*], + [1], [2], [3], [4], + [5], grid.cell(colspan: 3, fill: orange.darken(10%))[6], + grid.cell(colspan: 2, fill: orange)[7], [8], [9], + [10], grid.cell(colspan: 2, fill: orange.darken(10%))[11], [12] +) + +--- grid-rtl-colspan-stroke --- +#set text(dir: rtl) +#table( + columns: 4, + fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, + inset: 5pt, + align: center, + table.cell(colspan: 4)[*Full Header*], + table.cell(colspan: 2, fill: orange)[*Half*], + table.cell(colspan: 2, fill: orange.darken(10%))[*Half*], + [*A*], [*B*], [*C*], [*D*], + [1], [2], [3], [4], + [5], table.cell(colspan: 3, fill: orange.darken(10%))[6], + table.cell(colspan: 2, fill: orange)[7], [8], [9], + [10], table.cell(colspan: 2, fill: orange.darken(10%))[11], [12] +) + +#table( + columns: 4, + fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, + inset: 5pt, + align: center, + gutter: 3pt, + table.cell(colspan: 4)[*Full Header*], + table.cell(colspan: 2, fill: orange)[*Half*], + table.cell(colspan: 2, fill: orange.darken(10%))[*Half*], + [*A*], [*B*], [*C*], [*D*], + [1], [2], [3], [4], + [5], table.cell(colspan: 3, fill: orange.darken(10%))[6], + table.cell(colspan: 2, fill: orange)[7], [8], [9], + [10], table.cell(colspan: 2, fill: orange.darken(10%))[11], [12] +) + +--- grid-rtl-multiple-regions --- +// Test multiple regions +#set page(height: 5em) +#set text(dir: rtl) +#grid( + stroke: red, + fill: aqua, + columns: 4, + [a], [b], [c], [d], + [a], grid.cell(colspan: 2)[e, f, g, h, i], [f], + [e], [g], grid.cell(colspan: 2)[eee\ e\ e\ e], + grid.cell(colspan: 4)[eeee e e e] +) + +--- grid-rtl-vline-position --- +// Test left and right for vlines in RTL +#set text(dir: rtl) +#grid( + columns: 3, + inset: 5pt, + grid.vline(stroke: red, position: left), grid.vline(stroke: green, position: right), [a], + grid.vline(stroke: red, position: left), grid.vline(stroke: 2pt, position: right), [b], + grid.vline(stroke: red, position: left), grid.vline(stroke: 2pt, position: right), [c], + grid.vline(stroke: aqua, position: right) +) + +#grid( + columns: 3, + inset: 5pt, + gutter: 3pt, + grid.vline(stroke: green, position: left), grid.vline(stroke: red, position: right), [a], + grid.vline(stroke: blue, position: left), grid.vline(stroke: red, position: right), [b], + grid.vline(stroke: blue, position: left), grid.vline(stroke: red, position: right), [c], + grid.vline(stroke: 2pt, position: right) +) + +#grid( + columns: 3, + inset: 5pt, + grid.vline(stroke: green, position: start), grid.vline(stroke: red, position: end), [a], + grid.vline(stroke: 2pt, position: start), grid.vline(stroke: red, position: end), [b], + grid.vline(stroke: 2pt, position: start), grid.vline(stroke: red, position: end), [c], + grid.vline(stroke: 2pt, position: start) +) + +#grid( + columns: 3, + inset: 5pt, + gutter: 3pt, + grid.vline(stroke: green, position: start), grid.vline(stroke: red, position: end), [a], + grid.vline(stroke: blue, position: start), grid.vline(stroke: red, position: end), [b], + grid.vline(stroke: blue, position: start), grid.vline(stroke: red, position: end), [c], + grid.vline(stroke: 2pt, position: start) +) + +--- grid-rtl-vline-out-of-bounds --- +// Error: 3:8-3:34 cannot place vertical line at the 'end' position of the end border (x = 1) +// Hint: 3:8-3:34 set the line's position to 'start' or place it at a smaller 'x' index +#set text(dir: rtl) +#grid( + [a], grid.vline(position: left) +) + +--- grid-rtl-complex --- +#set text(dir: rtl) + +#grid( + columns: 4, + fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, + inset: 5pt, + align: center, + grid.cell(rowspan: 2, fill: orange)[*Left*], + [Right A], [Right A], [Right A], + [Right B], grid.cell(colspan: 2, rowspan: 2, fill: orange.darken(10%))[B Wide], + [Left A], [Left A], + [Left B], [Left B], grid.cell(colspan: 2, rowspan: 3, fill: orange)[Wide and Long] +) + +#table( + columns: 4, + fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, + inset: 5pt, + align: center, + gutter: 3pt, + table.cell(rowspan: 2, fill: orange)[*Left*], + [Right A], [Right A], [Right A], + [Right B], table.cell(colspan: 2, rowspan: 2, fill: orange.darken(10%))[B Wide], + [Left A], [Left A], + [Left B], [Left B], table.cell(colspan: 2, rowspan: 3, fill: orange)[Wide and Long] +) + +--- grid-rtl-rowspan --- +#set page(height: 10em) +#set text(dir: rtl) +#table( + columns: 2, + rows: (auto, auto, 3em), + row-gutter: 1em, + fill: red, + [a], table.cell(rowspan: 3, block(width: 50%, height: 10em, fill: orange) + place(bottom)[*ZD*]), + [e], + [f] +) + +--- grid-rtl-header --- +// Headers +#set page(height: 15em) +#set text(dir: rtl) +#table( + columns: 5, + align: center + horizon, + table.header( + table.cell(colspan: 5)[*Cool Zone*], + table.cell(stroke: red)[*N1*], table.cell(stroke: aqua)[*N2*], [*D1*], [*D2*], [*Etc*], + table.hline(start: 2, end: 3, stroke: yellow) + ), + ..range(0, 10).map(i => ([\##i], table.cell(stroke: green)[123], table.cell(stroke: blue)[456], [789], [?], table.hline(start: 4, end: 5, stroke: red))).flatten() +) diff --git a/tests/suite/layout/grid/stroke.typ b/tests/suite/layout/grid/stroke.typ new file mode 100644 index 00000000..9c1c3482 --- /dev/null +++ b/tests/suite/layout/grid/stroke.typ @@ -0,0 +1,435 @@ +--- grid-stroke-pattern --- +#let double-line = pattern(size: (1.5pt, 1.5pt), { + place(line(stroke: .6pt, start: (0%, 50%), end: (100%, 50%))) +}) + +#table( + stroke: (_, y) => if y != 1 { (bottom: black) }, + columns: 3, + table.cell(colspan: 3, align: center)[*Epic Table*], + align(center)[*Name*], align(center)[*Age*], align(center)[*Data*], + table.hline(stroke: (paint: double-line, thickness: 2pt)), + [John], [30], [None], + [Martha], [20], [A], + [Joseph], [35], [D] +) + +--- grid-stroke-folding --- +// Test folding +#set grid(stroke: red) +#set grid(stroke: 5pt) + +#grid( + inset: 10pt, + columns: 2, + stroke: stroke(dash: "loosely-dotted"), + grid.vline(start: 2, end: 3, stroke: (paint: green, dash: none)), + [a], [b], + grid.hline(end: 1, stroke: blue), + [c], [d], + [e], grid.cell(stroke: aqua)[f] +) + +--- grid-stroke-set-on-cell-and-line --- +// Test set rules on cells and folding +#set table.cell(stroke: 4pt) +#set table.cell(stroke: blue) +#set table.hline(stroke: red) +#set table.hline(stroke: 0.75pt) +#set table.vline(stroke: 0.75pt) +#set table.vline(stroke: aqua) + +#table( + columns: 3, + gutter: 3pt, + inset: 5pt, + [a], [b], table.vline(position: end), [c], + [d], [e], [f], + table.hline(position: bottom), + [g], [h], [i], +) + +--- grid-stroke-field-in-show --- +// Test stroke field on cell show rules +#set grid.cell(stroke: (x: 4pt)) +#set grid.cell(stroke: (x: blue)) +#show grid.cell: it => { + test(it.stroke, (left: stroke(paint: blue, thickness: 4pt, dash: "loosely-dotted"), right: blue + 4pt, top: stroke(thickness: 1pt), bottom: none)) + it +} +#grid( + stroke: (left: (dash: "loosely-dotted")), + inset: 5pt, + grid.hline(stroke: red), + grid.cell(stroke: (top: 1pt))[a], grid.vline(stroke: yellow), +) + +--- grid-stroke-complex --- +#table( + columns: 3, + [a], table.cell(colspan: 2)[b c], + table.cell(stroke: blue)[d], [e], [f], + [g], [h], table.cell(stroke: (left: yellow, top: green, right: aqua, bottom: red))[i], + [j], [k], [l], + table.cell(stroke: 3pt)[m], [n], table.cell(stroke: (dash: "loosely-dotted"))[o], +) + +--- grid-stroke-array --- +// Test per-column stroke array +#let t = table( + columns: 3, + stroke: (red, blue, green), + [a], [b], [c], + [d], [e], [f], + [h], [i], [j], +) +#t +#set text(dir: rtl) +#t + +--- grid-stroke-func --- +#grid( + columns: 3, + inset: 3pt, + stroke: (x, _) => (right: (5pt, (dash: "dotted")).at(calc.rem(x, 2)), bottom: (dash: "densely-dotted")), + grid.vline(x: 0, stroke: red), + grid.vline(x: 1, stroke: red), + grid.vline(x: 2, stroke: red), + grid.vline(x: 3, stroke: red), + grid.hline(y: 0, end: 1, stroke: blue), + grid.hline(y: 1, end: 1, stroke: blue), + grid.cell[a], + [b], [c] +) + +--- grid-stroke-manually-positioned-lines --- +#set page(height: 5em) +#table( + columns: 3, + inset: 3pt, + table.hline(y: 0, end: none, stroke: 3pt + blue), + table.vline(x: 0, end: none, stroke: 3pt + green), + table.hline(y: 5, end: none, stroke: 3pt + red), + table.vline(x: 3, end: none, stroke: 3pt + yellow), + [a], [b], [c], + [a], [b], [c], + [a], [b], [c], + [a], [b], [c], + [a], [b], [c], +) + +--- grid-stroke-automatically-positioned-lines --- +// Automatically positioned lines +// Plus stroke thickness ordering +#table( + columns: 3, + table.hline(stroke: red + 5pt), + table.vline(stroke: blue + 5pt), + table.vline(stroke: 2pt), + [a], + table.vline(x: 1, stroke: aqua + 5pt), + [b], + table.vline(stroke: aqua + 5pt), + [c], + table.vline(stroke: yellow + 5.2pt), + table.hline(stroke: green + 5pt), + [a], [b], [c], + [a], table.hline(stroke: green + 2pt), table.vline(stroke: 2pt), [b], [c], +) + +--- grid-stroke-priority-line --- +// Line specification order priority +// The last line should be blue, not red. +// The middle aqua line should be gone due to the 'none' override. +#grid( + columns: 2, + inset: 2pt, + grid.hline(y: 2, stroke: red + 5pt), + grid.vline(), + [a], [b], + grid.hline(stroke: red), + grid.hline(stroke: none), + [c], grid.cell(stroke: (top: aqua))[d], + grid.hline(stroke: blue), +) + +--- grid-stroke-hline-position-bottom-gutter --- +// Position: bottom and position: end with gutter should have a visible effect +// of moving the lines after the next track. +#table( + columns: 3, + gutter: 3pt, + stroke: blue, + table.hline(end: 2, stroke: red), + table.hline(end: 2, stroke: aqua, position: bottom), + table.vline(end: 2, stroke: green), [a], table.vline(end: 2, stroke: green), table.vline(end: 2, position: end, stroke: orange), [b], table.vline(end: 2, stroke: aqua, position: end), table.vline(end: 2, stroke: green), [c], table.vline(end: 2, stroke: green), + [d], [e], [f], + table.hline(end: 2, stroke: red), + [g], [h], [ie], + table.hline(end: 2, stroke: green), +) + +--- grid-stroke-hline-position-bottom --- +// Using position: bottom and position: end without gutter should be the same +// as placing a line after the next track. +#table( + columns: 3, + stroke: blue, + table.hline(end: 2, stroke: red), + table.hline(end: 2, stroke: aqua, position: bottom), + table.vline(end: 2, stroke: green), [a], table.vline(end: 2, stroke: green), [b], table.vline(end: 2, stroke: aqua, position: end), table.vline(end: 2, stroke: green), [c], table.vline(end: 2, stroke: green), + table.hline(end: 2, stroke: 5pt), + [d], [e], [f], + table.hline(end: 2, stroke: red), + [g], [h], [i], + table.hline(end: 2, stroke: red), +) + +--- grid-stroke-vline-position-left-and-right --- +// Test left and right for grid vlines. +#grid( + columns: 3, + inset: 5pt, + grid.vline(stroke: green, position: left), grid.vline(stroke: red, position: right), [a], + grid.vline(stroke: 2pt, position: left), grid.vline(stroke: red, position: right), [b], + grid.vline(stroke: 2pt, position: left), grid.vline(stroke: red, position: right), [c], + grid.vline(stroke: 2pt, position: left) +) + +#grid( + columns: 3, + inset: 5pt, + gutter: 3pt, + grid.vline(stroke: green, position: left), grid.vline(stroke: red, position: right), [a], + grid.vline(stroke: blue, position: left), grid.vline(stroke: red, position: right), [b], + grid.vline(stroke: blue, position: left), grid.vline(stroke: red, position: right), [c], + grid.vline(stroke: 2pt, position: left) +) + +--- table-stroke-vline-position-left-and-right --- +// Test left and right for table vlines. +#table( + columns: 3, + inset: 5pt, + table.vline(stroke: green, position: left), table.vline(stroke: red, position: right), [a], + table.vline(stroke: 2pt, position: left), table.vline(stroke: red, position: right), [b], + table.vline(stroke: 2pt, position: left), table.vline(stroke: red, position: right), [c], + table.vline(stroke: 2pt, position: left) +) + +#table( + columns: 3, + inset: 5pt, + gutter: 3pt, + table.vline(stroke: green, position: left), table.vline(stroke: red, position: right), [a], + table.vline(stroke: blue, position: left), table.vline(stroke: red, position: right), [b], + table.vline(stroke: blue, position: left), table.vline(stroke: red, position: right), [c], + table.vline(stroke: 2pt, position: left) +) + +--- grid-stroke-priority-line-cell --- +// Hlines and vlines should always appear on top of cell strokes. +#table( + columns: 3, + stroke: aqua, + table.vline(stroke: red, position: end), [a], table.vline(stroke: red), [b], [c], + table.cell(stroke: blue)[d], [e], [f], + table.hline(stroke: red), + [g], table.cell(stroke: blue)[h], [i], +) + +#table( + columns: 3, + gutter: 3pt, + stroke: aqua, + table.vline(stroke: red, position: end), [a], table.vline(stroke: red), [b], [c], + table.cell(stroke: blue)[d], [e], [f], + table.hline(stroke: red), + [g], table.cell(stroke: blue)[h], [i], +) + +--- grid-stroke-priority-cell --- +// Ensure cell stroke overrides always appear on top. +#table( + columns: 2, + stroke: black, + table.cell(stroke: red)[a], [b], + [c], [d], +) + +#table( + columns: 2, + table.cell(stroke: red)[a], [b], + [c], [d], +) + +--- grid-stroke-hline-position-bad --- +// Error: 7:3-7:32 cannot place horizontal line at the 'bottom' position of the bottom border (y = 2) +// Hint: 7:3-7:32 set the line's position to 'top' or place it at a smaller 'y' index +#table( + columns: 2, + [a], [b], + [c], [d], + table.hline(stroke: aqua), + table.hline(position: top), + table.hline(position: bottom) +) + +--- grid-stroke-border-partial --- +// Test partial border line overrides +#set page(width: auto, height: 7em, margin: (bottom: 1em)) +#table( + columns: 4, + stroke: (x, y) => if y == 0 or y == 4 { orange } else { aqua }, + table.hline(stroke: blue, start: 1, end: 2), table.cell(stroke: red, v(3em)), table.cell(stroke: blue)[b], table.cell(stroke: green)[c], [M], + [a], [b], [c], [M], + [d], [e], [f], [M], + [g], [h], [i], [M], + table.cell(stroke: red)[a], table.cell(stroke: blue)[b], table.cell(stroke: green)[c], [M], + table.hline(stroke: blue, start: 1, end: 2), +) + +--- grid-stroke-vline-colspan --- +// - Vline should be placed after the colspan. +// - Hline should be placed under the full-width rowspan. +#table( + columns: 3, + rows: 1.25em, + inset: 1pt, + stroke: none, + table.cell(colspan: 2)[a], table.vline(stroke: red), table.hline(stroke: blue), [b], + [c], [d], [e], + table.cell(colspan: 3, rowspan: 2)[a], table.vline(stroke: blue), table.hline(stroke: red) +) + +--- grid-stroke-hline-rowspan --- +// Red line should be above [c] (hline skips the shortest rowspan). +#set text(6pt) +#table( + rows: 1em, + columns: 2, + inset: 1.5pt, + table.cell(rowspan: 3)[a], table.cell(rowspan: 2)[b], + table.hline(stroke: red), + [c] +) + +--- grid-stroke-hline-position-bottom-out-of-bounds --- +// Error: 8:3-8:32 cannot place horizontal line at the 'bottom' position of the bottom border (y = 2) +// Hint: 8:3-8:32 set the line's position to 'top' or place it at a smaller 'y' index +#table( + columns: 2, + gutter: 3pt, + [a], [b], + [c], [d], table.vline(stroke: red), + table.hline(stroke: aqua), + table.hline(position: top), + table.hline(position: bottom) +) + +--- grid-stroke-vline-position-bottom-out-of-bounds --- +// Error: 6:3-6:28 cannot place vertical line at the 'end' position of the end border (x = 2) +// Hint: 6:3-6:28 set the line's position to 'start' or place it at a smaller 'x' index +#grid( + columns: 2, + [a], [b], + grid.vline(stroke: aqua), + grid.vline(position: start), + grid.vline(position: end) +) + +--- grid-stroke-vline-position-bottom-out-of-bounds-gutter --- +// Error: 7:3-7:28 cannot place vertical line at the 'end' position of the end border (x = 2) +// Hint: 7:3-7:28 set the line's position to 'start' or place it at a smaller 'x' index +#grid( + columns: 2, + gutter: 3pt, + [a], [b], + grid.vline(stroke: aqua), + grid.vline(position: start), + grid.vline(position: end) +) + +--- grid-stroke-hline-out-of-bounds --- +// Error: 4:3-4:19 cannot place horizontal line at invalid row 3 +#grid( + [a], + [b], + grid.hline(y: 3) +) + +--- grid-stroke-hline-out-of-bounds-gutter --- +// Error: 5:3-5:19 cannot place horizontal line at invalid row 3 +#grid( + gutter: 3pt, + [a], + [b], + grid.hline(y: 3) +) + +--- grid-stroke-vline-out-of-bounds --- +// Error: 4:3-4:20 cannot place vertical line at invalid column 3 +#table( + columns: 2, + [a], [b], + table.vline(x: 3) +) + +--- grid-stroke-vline-out-of-bounds-gutter --- +// Error: 5:3-5:20 cannot place vertical line at invalid column 3 +#table( + columns: 2, + gutter: 3pt, + [a], [b], + table.vline(x: 3) +) + +--- table-hline-in-grid --- +// Error: 7-20 cannot use `table.hline` as a grid line; use `grid.hline` instead +#grid(table.hline()) + +--- table-vline-in-grid --- +// Error: 7-20 cannot use `table.vline` as a grid line; use `grid.vline` instead +#grid(table.vline()) + +--- grid-hline-in-table --- +// Error: 8-20 cannot use `grid.hline` as a table line; use `table.hline` instead +#table(grid.hline()) + +--- grid-vline-in-table --- +// Error: 8-20 cannot use `grid.vline` as a table line; use `table.vline` instead +#table(grid.vline()) + +--- grid-hline-end-before-start-1 --- +// Error: 3:3-3:31 line cannot end before it starts +#grid( + columns: 3, + grid.hline(start: 2, end: 1), + [a], [b], [c], +) + +--- grid-hline-end-before-start-2 --- +// Error: 3:3-3:32 line cannot end before it starts +#table( + columns: 3, + table.vline(start: 2, end: 1), + [a], [b], [c], + [d], [e], [f], + [g], [h], [i], +) + +--- grid-hline-position-horizon --- +// Error: 24-31 expected `top` or `bottom`, found horizon +#table.hline(position: horizon) + +--- grid-vline-position-center --- +// Error: 24-30 expected `start`, `left`, `right`, or `end`, found center +#table.vline(position: center) + +--- grid-hline-position-right --- +// Error: 24-29 expected `top` or `bottom`, found right +#table.hline(position: right) + +--- grid-vline-position-top --- +// Error: 24-27 expected `start`, `left`, `right`, or `end`, found top +#table.vline(position: top) diff --git a/tests/suite/layout/grid/styling.typ b/tests/suite/layout/grid/styling.typ new file mode 100644 index 00000000..f7cfb97d --- /dev/null +++ b/tests/suite/layout/grid/styling.typ @@ -0,0 +1,160 @@ +// Test grid styling options. + +--- grid-fill-func --- +#set page(height: 70pt) +#set grid(fill: (x, y) => if calc.even(x + y) { rgb("aaa") }) + +#grid( + columns: (1fr,) * 3, + stroke: 2pt + rgb("333"), + [A], [B], [C], [], [], [D \ E \ F \ \ \ G], [H], +) + +--- grid-stroke-none --- +#grid(columns: 3, stroke: none, fill: green, [A], [B], [C]) + +--- grid-align --- +// Test general alignment. +#grid( + columns: 3, + align: left, + [Hello], [Hello], [Hello], + [A], [B], [C], +) + +// Test alignment with a function. +#grid( + columns: 3, + align: (x, y) => (left, center, right).at(x), + [Hello], [Hello], [Hello], + [A], [B], [C], +) + +// Test alignment with array. +#grid( + columns: (1fr, 1fr, 1fr), + align: (left, center, right), + [A], [B], [C] +) + +// Test empty array. +#set align(center) +#grid( + columns: (1fr, 1fr, 1fr), + align: (), + [A], [B], [C] +) + +a + +--- grid-inset --- +// Test inset. +#grid( + columns: (1fr,) * 3, + stroke: 2pt + rgb("333"), + inset: 5pt, + [A], [B], [C], [], [], [D \ E \ F \ \ \ G], [H], +) + +#grid( + columns: 3, + inset: 10pt, + fill: blue, + [A], [B], [C] +) + +#grid( + columns: 3, + inset: (y: 10pt), + [A], [B], [C] +) + +#grid( + columns: 3, + inset: (left: 20pt, rest: 10pt), + stroke: 3pt + red, + [A], [B], [C] +) + +#grid( + columns: 2, + inset: ( + left: 20pt, + right: 5pt, + top: 10pt, + bottom: 3pt, + ), + [A], + [B], +) + +#grid( + columns: 3, + fill: (x, y) => (if y == 0 { aqua } else { orange }).darken(x * 15%), + inset: (x, y) => (left: if x == 0 { 0pt } else { 5pt }, right: if x == 0 { 5pt } else { 0pt }, y: if y == 0 { 0pt } else { 5pt }), + [A], [B], [C], + [A], [B], [C], +) + +#grid( + columns: 3, + inset: (0pt, 5pt, 10pt), + fill: (x, _) => aqua.darken(x * 15%), + [A], [B], [C], +) + +--- grid-inset-folding --- +// Test inset folding +#set grid(inset: 10pt) +#set grid(inset: (left: 0pt)) + +#grid( + fill: red, + inset: (right: 0pt), + grid.cell(inset: (top: 0pt))[a] +) + +--- grid-funcs-gutter --- +// Test interaction with gutters. +#grid( + columns: (3em, 3em), + fill: (x, y) => (red, blue).at(calc.rem(x, 2)), + align: (x, y) => (left, right).at(calc.rem(y, 2)), + [A], [B], + [C], [D], + [E], [F], + [G], [H] +) + +#grid( + columns: (3em, 3em), + fill: (x, y) => (red, blue).at(calc.rem(x, 2)), + align: (x, y) => (left, right).at(calc.rem(y, 2)), + row-gutter: 5pt, + [A], [B], + [C], [D], + [E], [F], + [G], [H] +) + +#grid( + columns: (3em, 3em), + fill: (x, y) => (red, blue).at(calc.rem(x, 2)), + align: (x, y) => (left, right).at(calc.rem(y, 2)), + column-gutter: 5pt, + [A], [B], + [C], [D], + [E], [F], + [G], [H] +) + +#grid( + columns: (3em, 3em), + fill: (x, y) => (red, blue).at(calc.rem(x, 2)), + align: (x, y) => (left, right).at(calc.rem(y, 2)), + gutter: 5pt, + [A], [B], + [C], [D], + [E], [F], + [G], [H] +) diff --git a/tests/suite/layout/hide.typ b/tests/suite/layout/hide.typ new file mode 100644 index 00000000..a10090d7 --- /dev/null +++ b/tests/suite/layout/hide.typ @@ -0,0 +1,104 @@ +// Test the `hide` function. + +--- hide-text --- +AB #h(1fr) CD \ +#hide[A]B #h(1fr) C#hide[D] + +--- hide-line --- +Hidden: +#hide[#line(length: 100%)] +#line(length: 100%) + +--- hide-table --- +Hidden: +#hide(table(rows: 2, columns: 2)[a][b][c][d]) +#table(rows: 2, columns: 2)[a][b][c][d] + +--- hide-polygon --- +Hidden: +#hide[ + #polygon((20%, 0pt), + (60%, 0pt), + (80%, 2cm), + (0%, 2cm),) +] +#polygon((20%, 0pt), + (60%, 0pt), + (80%, 2cm), + (0%, 2cm),) + +--- hide-rect --- +#set rect( + inset: 8pt, + fill: rgb("e4e5ea"), + width: 100%, +) + +Hidden: +#hide[ +#grid( + columns: (1fr, 1fr, 2fr), + rows: (auto, 40pt), + gutter: 3pt, + rect[A], + rect[B], + rect[C], + rect(height: 100%)[D], +) +] +#grid( + columns: (1fr, 1fr, 2fr), + rows: (auto, 40pt), + gutter: 3pt, + rect[A], + rect[B], + rect[C], + rect(height: 100%)[D], +) + +--- hide-list --- +Hidden: +#hide[ +- 1 +- 2 + 1. A + 2. B +- 3 +] + + +- 1 +- 2 + 1. A + 2. B +- 3 + +--- hide-image --- +Hidden: +#hide(image("/assets/images/tiger.jpg", width: 5cm, height: 1cm,)) + +#image("/assets/images/tiger.jpg", width: 5cm, height: 1cm,) + +--- issue-622-hide-meta-cite --- +// Test that metadata of hidden stuff stays available. +#set cite(style: "chicago-notes") + +A pirate. @arrgh \ +#set text(2pt) +#hide[ + A @arrgh pirate. + #bibliography("/assets/bib/works.bib") +] + +--- issue-622-hide-meta-outline --- +#set text(8pt) +#outline() +#set text(2pt) +#hide(block(grid( + [= A], + [= B], + block(grid( + [= C], + [= D], + )) +))) diff --git a/tests/suite/layout/inline/baseline.typ b/tests/suite/layout/inline/baseline.typ new file mode 100644 index 00000000..e9f9a645 --- /dev/null +++ b/tests/suite/layout/inline/baseline.typ @@ -0,0 +1,17 @@ +// Test baseline handling. + +--- baseline-text --- +Hi #text(1.5em)[You], #text(0.75em)[how are you?] + +Our cockatoo was one of the +#text(baseline: -0.2em)[#box(circle(radius: 2pt)) first] +#text(baseline: 0.2em)[birds #box(circle(radius: 2pt))] +that ever learned to mimic a human voice. + +--- baseline-box --- +Hey #box(baseline: 40%, image("/assets/images/tiger.jpg", width: 1.5cm)) there! + +--- issue-2214-baseline-math --- +// The math content should also be affected by the TextElem baseline. +hello #text(baseline: -5pt)[123 #sym.WW\orld]\ +hello #text(baseline: -5pt)[$123 WW#text[or]$ld]\ diff --git a/tests/suite/layout/inline/bidi.typ b/tests/suite/layout/inline/bidi.typ new file mode 100644 index 00000000..7da23b41 --- /dev/null +++ b/tests/suite/layout/inline/bidi.typ @@ -0,0 +1,77 @@ +// Test bidirectional text and language configuration. + +--- bidi-en-he-top-level --- +// Test reordering with different top-level paragraph directions. +#let content = par[Text טֶקסט] +#text(lang: "he", content) +#text(lang: "de", content) + +--- bidi-consecutive-embedded-ltr-runs --- +// Test that consecutive, embedded LTR runs stay LTR. +// Here, we have two runs: "A" and italic "B". +#let content = par[أنت A#emph[B]مطرC] +#set text(font: ("PT Sans", "Noto Sans Arabic")) +#text(lang: "ar", content) +#text(lang: "de", content) + +--- bidi-consecutive-embedded-rtl-runs --- +// Test that consecutive, embedded RTL runs stay RTL. +// Here, we have three runs: "גֶ", bold "שֶׁ", and "ם". +#let content = par[Aגֶ#strong[שֶׁ]םB] +#set text(font: ("Linux Libertine", "Noto Serif Hebrew")) +#text(lang: "he", content) +#text(lang: "de", content) + +--- bidi-nesting --- +// Test embedding up to level 4 with isolates. +#set text(dir: rtl) +א\u{2066}A\u{2067}Bב\u{2069}? + +--- bidi-manual-linebreak --- +// Test hard line break (leads to two paragraphs in unicode-bidi). +#set text(lang: "ar", font: ("Noto Sans Arabic", "PT Sans")) +Life المطر هو الحياة \ +الحياة تمطر is rain. + +--- bidi-spacing --- +// Test spacing. +L #h(1cm) ריווחR \ +Lריווח #h(1cm) R + +--- bidi-obj --- +// Test inline object. +#set text(lang: "he") +קרנפיםRh#box(image("/assets/images/rhino.png", height: 11pt))inoחיים + +--- bidi-whitespace-reset --- +// Test whether L1 whitespace resetting destroys stuff. +الغالب #h(70pt) ن#" "ة + +--- bidi-explicit-dir --- +// Test explicit dir +#set text(dir: rtl) +#text("8:00 - 9:00", dir: ltr) בבוקר +#linebreak() +ב #text("12:00 - 13:00", dir: ltr) בצהריים + +--- bidi-raw --- +// Mixing raw +#set text(lang: "he") +לדוג. `if a == b:` זה תנאי +#set raw(lang: "python") +לדוג. `if a == b:` זה תנאי + +#show raw: set text(dir:rtl) +לתכנת בעברית `אם א == ב:` + +--- bidi-vertical --- +// Test setting a vertical direction. +// Error: 16-19 text direction must be horizontal +#set text(dir: ttb) + +--- issue-1373-bidi-tofus --- +// Test that shaping missing characters in both left-to-right and +// right-to-left directions does not cause a crash. +#"\u{590}\u{591}\u{592}\u{593}" + +#"\u{30000}\u{30001}\u{30002}\u{30003}" diff --git a/tests/suite/layout/inline/cjk.typ b/tests/suite/layout/inline/cjk.typ new file mode 100644 index 00000000..0540cd19 --- /dev/null +++ b/tests/suite/layout/inline/cjk.typ @@ -0,0 +1,90 @@ +// Test CJK-specific features. + +--- text-chinese-basic --- +// Test basic Chinese text from Wikipedia. +#set text(font: "Noto Serif CJK SC") + +是美国广播公司电视剧《迷失》第3季的第22和23集,也是全剧的第71集和72集 +由执行制作人戴蒙·林道夫和卡尔顿·库斯编剧,导演则是另一名执行制作人杰克·本德 +节目于2007年5月23日在美国和加拿大首播,共计吸引了1400万美国观众收看 +本集加上插播广告一共也持续有两个小时 + +--- text-cjk-latin-spacing --- +#set page(width: 50pt + 10pt, margin: (x: 5pt)) +#set text(lang: "zh", font: "Noto Serif CJK SC", cjk-latin-spacing: auto) +#set par(justify: true) + +中文,中12文1中,文12中文 + +中文,中ab文a中,文ab中文 + +#set text(cjk-latin-spacing: none) + +中文,中12文1中,文12中文 + +中文,中ab文a中,文ab中文 + +--- cjk-punctuation-adjustment-1 --- +#set page(width: 15em) + +// In the following example, the space between 》! and ? should be squeezed. +// because zh-CN follows GB style +#set text(lang: "zh", region: "CN", font: "Noto Serif CJK SC") +原来,你也玩《原神》!? + +// However, in the following example, the space between 》! and ? should not be squeezed. +// because zh-TW does not follow GB style +#set text(lang: "zh", region: "TW", font: "Noto Serif CJK TC") +原來,你也玩《原神》! ? + +#set text(lang: "zh", region: "CN", font: "Noto Serif CJK SC") +「真的吗?」 + +#set text(lang: "ja", font: "Noto Serif CJK JP") +「本当に?」 + +--- cjk-punctuation-adjustment-2 --- +#set text(lang: "zh", region: "CN", font: "Noto Serif CJK SC") +《书名〈章节〉》 // the space between 〉 and 》 should be squeezed + +〔茸毛〕:很细的毛 // the space between 〕 and : should be squeezed + +--- cjk-punctuation-adjustment-3 --- +#set page(width: 21em) +#set text(lang: "zh", region: "CN", font: "Noto Serif CJK SC") + +// These examples contain extensive use of Chinese punctuation marks, +// from 《Which parentheses should be used when applying parentheses?》. +// link: https://archive.md/2bb1N + + +(〔中〕医、〔中〕药、技)系列评审 + +(长三角[长江三角洲])(GB/T 16159—2012《汉语拼音正词法基本规则》) + +【爱因斯坦(Albert Einstein)】物理学家 + +〔(2009)民申字第1622号〕 + +“江南海北长相忆,浅水深山独掩扉。”([唐]刘长卿《会赦后酬主簿所问》) + +参看1378页〖象形文字〗。(《现代汉语词典》修订本) + +--- issue-2538-cjk-latin-spacing-before-linebreak --- +// Issue #2538 +#set text(cjk-latin-spacing: auto) + +abc字 + +abc字#linebreak() + +abc字#linebreak() +母 + +abc字\ +母 + +--- issue-2650-cjk-latin-spacing-meta --- +测a试 + +测#context [a]试 diff --git a/tests/suite/layout/inline/hyphenate.typ b/tests/suite/layout/inline/hyphenate.typ new file mode 100644 index 00000000..aaabe816 --- /dev/null +++ b/tests/suite/layout/inline/hyphenate.typ @@ -0,0 +1,51 @@ +// Test hyphenation. + +--- hyphenate --- +// Test hyphenating english and greek. +#set text(hyphenate: true) +#set page(width: auto) +#grid( + columns: (50pt, 50pt), + [Warm welcomes to Typst.], + text(lang: "el")[διαμερίσματα. \ λατρευτός], +) + +--- hyphenate-off-temporarily --- +// Test disabling hyphenation for short passages. +#set page(width: 110pt) +#set text(hyphenate: true) + +Welcome to wonderful experiences. \ +Welcome to `wonderful` experiences. \ +Welcome to #text(hyphenate: false)[wonderful] experiences. \ +Welcome to wonde#text(hyphenate: false)[rf]ul experiences. \ + +// Test enabling hyphenation for short passages. +#set text(hyphenate: false) +Welcome to wonderful experiences. \ +Welcome to wo#text(hyphenate: true)[nd]erful experiences. \ + +--- hyphenate-between-shape-runs --- +// Hyphenate between shape runs. +#set page(width: 80pt) +#set text(hyphenate: true) +It's a #emph[Tree]beard. + +--- hyphenate-shy --- +// Test shy hyphens. +#set text(lang: "de", hyphenate: true) +#grid( + columns: 2 * (20pt,), + gutter: 20pt, + [Barankauf], + [Bar-?ankauf], +) + +--- hyphenate-punctuation --- +// This sequence would confuse hypher if we passed trailing / leading +// punctuation instead of just the words. So this tests that we don't +// do that. The test passes if there's just one hyphenation between +// "net" and "works". +#set page(width: 60pt) +#set text(hyphenate: true) +#h(6pt) networks, the rest. diff --git a/tests/suite/layout/inline/justify.typ b/tests/suite/layout/inline/justify.typ new file mode 100644 index 00000000..e1e15578 --- /dev/null +++ b/tests/suite/layout/inline/justify.typ @@ -0,0 +1,170 @@ +--- justify --- +#set page(width: 180pt) +#set block(spacing: 5pt) +#set par(justify: true, first-line-indent: 14pt, leading: 5pt) + +This text is justified, meaning that spaces are stretched so that the text +forms a "block" with flush edges at both sides. + +First line indents and hyphenation play nicely with justified text. + +--- justify-knuth-story --- +// LARGE +#set page(width: auto, height: auto) +#set par(leading: 4pt, justify: true) +#set text(font: "New Computer Modern") + +#let story = [ + In olden times when wishing still helped one, there lived a king whose + daughters were all beautiful; and the youngest was so beautiful that the sun + itself, which has seen so much, was astonished whenever it shone in her face. + Close by the king’s castle lay a great dark forest, and under an old lime-tree + in the forest was a well, and when the day was very warm, the king’s child + went out into the forest and sat down by the side of the cool fountain; and + when she was bored she took a golden ball, and threw it up on high and caught + it; and this ball was her favorite plaything. +] + +#let column(title, linebreaks, hyphenate) = { + rect(inset: 0pt, width: 132pt, fill: rgb("eee"))[ + #set par(linebreaks: linebreaks) + #set text(hyphenate: hyphenate) + #strong(title) \ #story + ] +} + +#grid( + columns: 3, + gutter: 10pt, + column([Simple without hyphens], "simple", false), + column([Simple with hyphens], "simple", true), + column([Optimized with hyphens], "optimized", true), +) + +--- justify-manual-linebreak --- +// Test that lines with hard breaks aren't justified. +#set par(justify: true) +A B C \ +D + +--- justify-justified-linebreak --- +// Test forced justification with justified break. +A B C #linebreak(justify: true) +D E F #linebreak(justify: true) + +--- justify-basically-empty --- +// Test that there are no hick-ups with justification enabled and +// basically empty paragraph. +#set par(justify: true) +#"" + +--- justify-shrink-last-line --- +// Test that the last line can be shrunk +#set page(width: 155pt) +#set par(justify: true) +This text can be fitted in one line. + +--- justify-avoid-runts --- +// Test that runts are avoided when it's not too costly to do so. +#set page(width: 124pt) +#set par(justify: true) +#for i in range(0, 20) { + "a b c " +} +#"d" + +--- justify-no-leading-spaces --- +// Test that justification cannot lead to a leading space +#set par(justify: true) +#set text(size: 12pt) +#set page(width: 45mm, height: auto) + +lorem ipsum 1234, lorem ipsum dolor sit amet + +#" leading whitespace should still be displayed" + +--- justify-code-blocks --- +// Test that justification doesn't break code blocks +#set par(justify: true) + +```cpp +int main() { + printf("Hello world\n"); + return 0; +} +``` + +--- justify-chinese --- +// In Chinese typography, line length should be multiples of the character size +// and the line ends should be aligned with each other. Most Chinese +// publications do not use hanging punctuation at line end. +#set page(width: auto) +#set par(justify: true) +#set text(lang: "zh", font: "Noto Serif CJK SC") + +#rect(inset: 0pt, width: 80pt, fill: rgb("eee"))[ + 中文维基百科使用汉字书写,汉字是汉族或华人的共同文字,是中国大陆、新加坡、马来西亚、台湾、香港、澳门的唯一官方文字或官方文字之一。25.9%,而美国和荷兰则分別占13.7%及8.2%。近年來,中国大陆地区的维基百科编辑者正在迅速增加; +] + +--- justify-japanese --- +// Japanese typography is more complex, make sure it is at least a bit sensible. +#set page(width: auto) +#set par(justify: true) +#set text(lang: "ja", font: ("Linux Libertine", "Noto Serif CJK JP")) +#rect(inset: 0pt, width: 80pt, fill: rgb("eee"))[ + ウィキペディア(英: Wikipedia)は、世界中のボランティアの共同作業によって執筆及び作成されるフリーの多言語インターネット百科事典である。主に寄付に依って活動している非営利団体「ウィキメディア財団」が所有・運営している。 + + 専門家によるオンライン百科事典プロジェクトNupedia(ヌーペディア)を前身として、2001年1月、ラリー・サンガーとジミー・ウェールズ(英: Jimmy Donal "Jimbo" Wales)により英語でプロジェクトが開始された。 +] + +--- justify-whitespace-adjustment --- +// Test punctuation whitespace adjustment +#set page(width: auto) +#set text(lang: "zh", font: "Noto Serif CJK SC") +#set par(justify: true) +#rect(inset: 0pt, width: 80pt, fill: rgb("eee"))[ + “引号测试”,还, + + 《书名》《测试》下一行 + + 《书名》《测试》。 +] + +「『引号』」。“‘引号’”。 + +--- justify-variants --- +// Test Variants of Mainland China, Hong Kong, and Japan. + +// 17 characters a line. +#set page(width: 170pt + 10pt, margin: (x: 5pt)) +#set text(lang: "zh", font: "Noto Serif CJK SC") +#set par(justify: true) + +孔雀最早见于《山海经》中的《海内经》:“有孔雀。”东汉杨孚著《异物志》记载,岭南:“孔雀,其大如大雁而足高,毛皆有斑纹彩,捕而蓄之,拍手即舞。” + +#set text(lang: "zh", region: "hk", font: "Noto Serif CJK TC") +孔雀最早见于《山海经》中的《海内经》:「有孔雀。」东汉杨孚著《异物志》记载,岭南:「孔雀,其大如大雁而足高,毛皆有斑纹彩,捕而蓄之,拍手即舞。」 + +--- justify-punctuation-adjustment --- +// Test punctuation marks adjustment in justified paragraph. + +// The test case includes the following scenarios: +// - Compression of punctuation marks at line start or line end +// - Adjustment of adjacent punctuation marks + +#set page(width: 110pt + 10pt, margin: (x: 5pt)) +#set text(lang: "zh", font: "Noto Serif CJK SC") +#set par(justify: true) + +标注在字间的标点符号(乙式括号省略号以外)通常占一个汉字宽度,使其易于识别、适合配置及排版,有些排版风格完全不对标点宽度进行任何调整。但是为了让文字体裁更加紧凑易读,,,以及执行3.1.4 行首行尾禁则时,就需要对标点符号的宽度进行调整。是否调整取决于…… + +--- justify-without-justifiables --- +// Test breaking a line without justifiables. +#set par(justify: true) +#block(width: 1cm, fill: aqua, lorem(2)) + +--- issue-2419-justify-hanging-indent --- +// Test that combination of justification and hanging indent doesn't result in +// an underfull first line. +#set par(hanging-indent: 2.5cm, justify: true) +#lorem(5) diff --git a/tests/suite/layout/inline/linebreak.typ b/tests/suite/layout/inline/linebreak.typ new file mode 100644 index 00000000..2fa29b6c --- /dev/null +++ b/tests/suite/layout/inline/linebreak.typ @@ -0,0 +1,109 @@ +// Test line breaks. + +--- linebreak-overflow --- +// Test overlong word that is not directly after a hard break. +This is a spaceexceedinglylongy. + +--- linebreak-overflow-double --- +// Test two overlong words in a row. +Supercalifragilisticexpialidocious Expialigoricmetrioxidation. + +--- linebreak-hyphen-nbsp --- +// Test for non-breaking space and hyphen. +There are non\u{2011}breaking~characters. + +--- linebreak-narrow-nbsp --- +// Test for narrow non-breaking space. +#show "_": sym.space.nobreak.narrow +0.1_g, 1_g, 10_g, 100_g, 1_000_g, 10_000_g, 100_000_g, 1_000_000_g + +--- linebreak-shape-run --- +// Test that there are no unwanted line break opportunities on run change. +This is partly emp#emph[has]ized. + +--- linebreak-manual --- +Hard #linebreak() break. + +--- linebreak-manual-directly-after-automatic --- +// Test hard break directly after normal break. +Hard break directly after \ normal break. + +--- linebreak-manual-consecutive --- +// Test consecutive breaks. +Two consecutive \ \ breaks and three \ \ more. + +--- linebreak-manual-trailing-multiple --- +// Test forcing an empty trailing line. +Trailing break \ \ + +--- linebreak-manual-justified --- +// Test justified breaks. +#set par(justify: true) +With a soft #linebreak(justify: true) +break you can force a break without #linebreak(justify: true) +breaking justification. #linebreak(justify: false) +Nice! + +--- linebreak-thai --- +// Test linebreak for East Asian languages +ทีวีตรวจทานนอร์ทแฟรีเลคเชอร์โกลด์อัลบัมเชอร์รี่เย้วสโตร์กฤษณ์เคลมเยอบีร่าพ่อค้าบลูเบอร์รี่สหัสวรรษโฮปแคนูโยโย่จูนสตรอว์เบอร์รีซื่อบื้อเยนแบ็กโฮเป็นไงโดนัททอมสเตริโอแคนูวิทย์แดรี่โดนัทวิทย์แอปพริคอทเซอร์ไพรส์ไฮบริดกิฟท์อินเตอร์โซนเซอร์วิสเทียมทานโคโยตี้ม็อบเที่ยงคืนบุญคุณ + +--- linebreak-cite-punctuation --- +// Test punctuation after citations. +#set page(width: 162pt) + +They can look for the details in @netwok, +which is the authoritative source. + +#bibliography("/assets/bib/works.bib") + +--- linebreak-math-punctuation --- +// Test punctuation after math equations. +#set page(width: 85pt) + +We prove $1 < 2$. \ +We prove $1 < 2$! \ +We prove $1 < 2$? \ +We prove $1 < 2$, \ +We prove $1 < 2$; \ +We prove $1 < 2$: \ +We prove $1 < 2$- \ +We prove $1 < 2$– \ +We prove $1 < 2$— \ + +--- linebreak-link --- +#link("https://example.com/(ab") \ +#link("https://example.com/(ab)") \ +#link("https://example.com/(paren)") \ +#link("https://example.com/paren)") \ +#link("https://hi.com/%%%%%%%%abcdef") \ + +--- linebreak-link-justify --- +#set page(width: 240pt) +#set par(justify: true) + +Here's a link https://url.com/data/extern12840%data_urlenc and then there are more +links #link("www.url.com/data/extern12840%data_urlenc") in my text of links +http://mydataurl/hash/12098541029831025981024980124124214/incremental/progress%linkdata_information_setup_my_link_just_never_stops_going/on?query=false + +--- linebreak-link-end --- +// Ensure that there's no unconditional break at the end of a link. +#set page(width: 180pt, height: auto, margin: auto) +#set text(11pt) + +For info see #link("https://myhost.tld"). + +--- issue-2105-linebreak-tofu --- +#linebreak()中文 + +--- issue-3082-chinese-punctuation --- +#set text(font: "Noto Serif CJK TC", lang: "zh") +#set page(width: 230pt) + +課有手冬,朱得過已誰卜服見以大您即乙太邊良,因且行肉因和拉幸,念姐遠米巴急(abc0),松黃貫誰。 + +--- issue-80-emoji-linebreak --- +// Test that there are no linebreaks in composite emoji (issue #80). +#set page(width: 50pt, height: auto) +#h(99%) 🏳️🌈 +🏳️🌈 diff --git a/tests/suite/layout/inline/overhang.typ b/tests/suite/layout/inline/overhang.typ new file mode 100644 index 00000000..40b0e7f7 --- /dev/null +++ b/tests/suite/layout/inline/overhang.typ @@ -0,0 +1,24 @@ +// Test micro-typographical shenanigans. + +--- overhang --- +// Test hanging punctuation. +// TODO: This test was broken at some point. +#set page(width: 130pt, margin: 15pt) +#set par(justify: true, linebreaks: "simple") +#set text(size: 9pt) +#rect(inset: 0pt, fill: rgb(0, 0, 0, 0), width: 100%)[ + This is a little bit of text that builds up to + hang-ing hyphens and dash---es and then, you know, + some punctuation in the margin. +] + +// Test hanging punctuation with RTL. +#set text(lang: "he", font: ("PT Sans", "Noto Serif Hebrew")) +בנייה נכונה של משפטים ארוכים דורשת ידע בשפה. אז בואו נדבר על מזג האוויר. + +--- overhang-lone --- +// Test that lone punctuation doesn't overhang into the margin. +#set page(margin: 0pt) +#set align(end) +#set text(dir: rtl) +: diff --git a/tests/suite/layout/inline/shaping.typ b/tests/suite/layout/inline/shaping.typ new file mode 100644 index 00000000..ec93eb47 --- /dev/null +++ b/tests/suite/layout/inline/shaping.typ @@ -0,0 +1,65 @@ +// Test shaping quirks. + +--- shaping-script-separation --- +// Test separation by script. +#set text(font: ("Linux Libertine", "IBM Plex Sans Devanagari")) +ABCअपार्टमेंट + +// This is how it should look like. +अपार्टमेंट + +// This (without the spaces) is how it would look +// if we didn't separate by script. +अ पा र् ट में ट + +--- shaping-forced-script-font-feature-inhibited --- +// A forced `latn` script inhibits Devanagari font features. +#set text(font: ("Linux Libertine", "IBM Plex Sans Devanagari"), script: "latn") +ABCअपार्टमेंट + +--- shaping-forced-script-font-feature-enabled --- +// A forced `deva` script enables Devanagari font features. +#set text(font: ("Linux Libertine", "IBM Plex Sans Devanagari"), script: "deva") +ABCअपार्टमेंट + +--- issue-rtl-safe-to-break-panic --- +// Test that RTL safe-to-break doesn't panic even though newline +// doesn't exist in shaping output. +#set text(dir: rtl, font: "Noto Serif Hebrew") +\ ט + +--- shaping-font-fallback --- +// Font fallback for emoji. +A😀B + +// Font fallback for entire text. +دع النص يمطر عليك + +// Font fallback in right-to-left text. +ب🐈😀سم + +// Multi-layer font fallback. +Aب😀🏞سمB + +// Font fallback with composed emojis and multiple fonts. +01️⃣2 + +// Tofus are rendered with the first font. +A🐈ዲሞB + +--- shaping-emoji-basic --- +// This should form a three-member family. +👩👩👦 + +// This should form a pride flag. +🏳️🌈 + +// Skin tone modifier should be applied. +👍🏿 + +// This should be a 1 in a box. +1️⃣ + +--- shaping-emoji-bad-zwj --- +// These two shouldn't be affected by a zero-width joiner. +🏞🌋 diff --git a/tests/suite/layout/inline/text.typ b/tests/suite/layout/inline/text.typ new file mode 100644 index 00000000..e2bc84ef --- /dev/null +++ b/tests/suite/layout/inline/text.typ @@ -0,0 +1,89 @@ +// Test OpenType features. + +--- text-kerning --- +// Test turning kerning off. +#text(kerning: true)[Tq] \ +#text(kerning: false)[Tq] + +--- text-alternates-and-stylistic-sets --- +// Test alternates and stylistic sets. +#set text(font: "IBM Plex Serif") +a vs #text(alternates: true)[a] \ +ß vs #text(stylistic-set: 5)[ß] + +--- text-ligatures --- +// Test ligatures. +fi vs. #text(ligatures: false)[No fi] + +--- text-number-type --- +// Test number type. +#set text(number-type: "old-style") +0123456789 \ +#text(number-type: auto)[0123456789] + +--- text-number-width --- +// Test number width. +#text(number-width: "proportional")[0123456789] \ +#text(number-width: "tabular")[3456789123] \ +#text(number-width: "tabular")[0123456789] + +--- text-slashed-zero-and-fractions --- +// Test extra number stuff. +#set text(font: "IBM Plex Serif") +0 vs. #text(slashed-zero: true)[0] \ +1/2 vs. #text(fractions: true)[1/2] + +--- text-features --- +// Test raw features. +#text(features: ("smcp",))[Smcp] \ +fi vs. #text(features: (liga: 0))[No fi] + +--- text-stylistic-set-bad-type --- +// Error: 26-31 expected integer or none, found boolean +#set text(stylistic-set: false) + +--- text-stylistic-set-out-of-bounds --- +// Error: 26-28 stylistic set must be between 1 and 20 +#set text(stylistic-set: 25) + +--- text-number-type-bad --- +// Error: 24-25 expected "lining", "old-style", or auto, found integer +#set text(number-type: 2) + +--- text-features-bad --- +// Error: 21-26 expected array or dictionary, found boolean +#set text(features: false) + +--- text-features-bad-nested-type --- +// Error: 21-35 expected string, found boolean +#set text(features: ("tag", false)) + +--- text-tracking-negative --- +// Test tracking. +#set text(tracking: -0.01em) +I saw Zoe yӛsterday, on the tram. + +--- text-tracking-changed-temporarily --- +// Test tracking for only part of paragraph. +I'm in#text(tracking: 0.15em + 1.5pt)[ spaace]! + +--- text-tracking-mark-placement --- +// Test that tracking doesn't disrupt mark placement. +#set text(font: ("PT Sans", "Noto Serif Hebrew")) +#set text(tracking: 0.3em) +טֶקסט + +--- text-tracking-arabic --- +// Test tracking in arabic text (makes no sense whatsoever) +#set text(tracking: 0.3em) +النص + +--- text-spacing --- +// Test word spacing. +#set text(spacing: 1em) +My text has spaces. + +--- text-spacing-relative --- +// Test word spacing relative to the font's space width. +#set text(spacing: 50% + 1pt) +This is tight. diff --git a/tests/suite/layout/layout.typ b/tests/suite/layout/layout.typ new file mode 100644 index 00000000..257e478b --- /dev/null +++ b/tests/suite/layout/layout.typ @@ -0,0 +1,14 @@ +--- layout-in-fixed-size-block --- +// Layout inside a block with certain dimensions should provide those dimensions. +#set page(height: 120pt) +#block(width: 60pt, height: 80pt, layout(size => [ + This block has a width of #size.width and height of #size.height +])) + +--- layout-in-page-call --- +// Layout without any container should provide the page's dimensions, minus its margins. +#page(width: 100pt, height: 100pt, { + layout(size => [This page has a width of #size.width and height of #size.height ]) + h(1em) + place(left, rect(width: 80pt, stroke: blue)) +}) diff --git a/tests/suite/layout/length.typ b/tests/suite/layout/length.typ new file mode 100644 index 00000000..68755619 --- /dev/null +++ b/tests/suite/layout/length.typ @@ -0,0 +1,69 @@ +--- length-fields --- +// Test length fields. +#test((1pt).em, 0.0) +#test((1pt).abs, 1pt) +#test((3em).em, 3.0) +#test((3em).abs, 0pt) +#test((2em + 2pt).em, 2.0) +#test((2em + 2pt).abs, 2pt) + +--- length-to-unit --- +// Test length unit conversions. +#test((500.934pt).pt(), 500.934) +#test((3.3453cm).cm(), 3.3453) +#test((4.3452mm).mm(), 4.3452) +#test((5.345in).inches(), 5.345) +#test((500.333666999pt).pt(), 500.333666999) +#test((3.5234354cm).cm(), 3.5234354) +#test((4.12345678mm).mm(), 4.12345678) +#test((5.333666999in).inches(), 5.333666999) +#test((4.123456789123456mm).mm(), 4.123456789123456) +#test((254cm).mm(), 2540.0) +#test(calc.round((254cm).inches(), digits: 2), 100.0) +#test((2540mm).cm(), 254.0) +#test(calc.round((2540mm).inches(), digits: 2), 100.0) +#test((100in).pt(), 7200.0) +#test(calc.round((100in).cm(), digits: 2), 254.0) +#test(calc.round((100in).mm(), digits: 2), 2540.0) +#test(5em.abs.cm(), 0.0) +#test((5em + 6in).abs.inches(), 6.0) + +--- length-to-absolute --- +// Test length `to-absolute` method. +#set text(size: 12pt) +#context { + test((6pt).to-absolute(), 6pt) + test((6pt + 10em).to-absolute(), 126pt) + test((10em).to-absolute(), 120pt) +} + +#set text(size: 64pt) +#context { + test((6pt).to-absolute(), 6pt) + test((6pt + 10em).to-absolute(), 646pt) + test((10em).to-absolute(), 640pt) +} + +--- length-unit-hint --- +// Error: 1:17-1:19 expected length, found integer: a length needs a unit - did you mean 12pt? +#set text(size: 12) + +--- length-ignore-em-pt-hint --- +// Error: 2-21 cannot convert a length with non-zero em units (`-6pt + 10.5em`) to pt +// Hint: 2-21 use `length.abs.pt()` instead to ignore its em component +#(10.5em - 6pt).pt() + +--- length-ignore-em-cm-hint --- +// Error: 2-12 cannot convert a length with non-zero em units (`3em`) to cm +// Hint: 2-12 use `length.abs.cm()` instead to ignore its em component +#(3em).cm() + +--- length-ignore-em-mm-hint --- +// Error: 2-20 cannot convert a length with non-zero em units (`-226.77pt + 93em`) to mm +// Hint: 2-20 use `length.abs.mm()` instead to ignore its em component +#(93em - 80mm).mm() + +--- length-ignore-em-inches-hint --- +// Error: 2-24 cannot convert a length with non-zero em units (`432pt + 4.5em`) to inches +// Hint: 2-24 use `length.abs.inches()` instead to ignore its em component +#(4.5em + 6in).inches() diff --git a/tests/suite/layout/limits.typ b/tests/suite/layout/limits.typ new file mode 100644 index 00000000..e1f0ec5f --- /dev/null +++ b/tests/suite/layout/limits.typ @@ -0,0 +1,32 @@ +// Test how the layout engine reacts when reaching limits like +// zero, infinity or when dealing with NaN. + +--- issue-1216-clamp-panic --- +#set page(height: 20pt, margin: 0pt) +#v(22pt) +#block(fill: red, width: 100%, height: 10pt, radius: 4pt) + +--- issue-1918-layout-infinite-length-grid-columns --- +// Test that passing infinite lengths to drawing primitives does not crash Typst. +#set page(width: auto, height: auto) + +// Error: 58-59 cannot expand into infinite width +#layout(size => grid(columns: (size.width, size.height))[a][b][c][d]) + +--- issue-1918-layout-infinite-length-grid-rows --- +#set page(width: auto, height: auto) + +// Error: 17-66 cannot create grid with infinite height +#layout(size => grid(rows: (size.width, size.height))[a][b][c][d]) + +--- issue-1918-layout-infinite-length-line --- +#set page(width: auto, height: auto) + +// Error: 17-41 cannot create line with infinite length +#layout(size => line(length: size.width)) + +--- issue-1918-layout-infinite-length-polygon --- +#set page(width: auto, height: auto) + +// Error: 17-54 cannot create polygon with infinite size +#layout(size => polygon((0pt,0pt), (0pt, size.width))) diff --git a/tests/suite/layout/measure.typ b/tests/suite/layout/measure.typ new file mode 100644 index 00000000..5f82e915 --- /dev/null +++ b/tests/suite/layout/measure.typ @@ -0,0 +1,9 @@ +--- measure --- +// Test `measure`. +#let f(lo, hi) = context { + let h = measure[Hello].height + assert(h > lo) + assert(h < hi) +} +#text(10pt, f(6pt, 8pt)) +#text(20pt, f(13pt, 14pt)) diff --git a/tests/suite/layout/pad.typ b/tests/suite/layout/pad.typ new file mode 100644 index 00000000..3a7439d0 --- /dev/null +++ b/tests/suite/layout/pad.typ @@ -0,0 +1,30 @@ +// Test the `pad` function. + +--- pad-basic --- +// Use for indentation. +#pad(left: 10pt, [Indented!]) + +// All sides together. +#set rect(inset: 0pt) +#rect(fill: conifer, + pad(10pt, right: 20pt, + rect(width: 20pt, height: 20pt, fill: rgb("eb5278")) + ) +) + +Hi #box(pad(left: 10pt)[A]) there + +--- pad-expanding-contents --- +// Pad can grow. +#pad(left: 10pt, right: 10pt)[PL #h(1fr) PR] + +--- pad-followed-by-content --- +// Test that the pad element doesn't consume the whole region. +#set page(height: 6cm) +#align(left)[Before] +#pad(10pt, image("/assets/images/tiger.jpg")) +#align(right)[After] + +--- pad-adding-to-100-percent --- +// Test that padding adding up to 100% does not panic. +#pad(50%)[] diff --git a/tests/suite/layout/page.typ b/tests/suite/layout/page.typ new file mode 100644 index 00000000..a529b429 --- /dev/null +++ b/tests/suite/layout/page.typ @@ -0,0 +1,231 @@ +// Test the page class. + +--- page-call-empty --- +// Just empty page. +// Should result in auto-sized page, just like nothing. +#page[] + +--- page-call-styled-empty --- +// Just empty page with styles. +// Should result in one conifer-colored A11 page. +#page("a11", flipped: true, fill: conifer)[] + +--- page-call-followed-by-pagebreak --- +// Just page followed by pagebreak. +// Should result in one forest-colored A11 page and one auto-sized page. +#page("a11", flipped: true, fill: forest)[] +#pagebreak() + +--- page-set-forces-break --- +// Set width and height. +// Should result in one high and one wide page. +#set page(width: 80pt, height: 80pt) +#[#set page(width: 40pt);High] +#[#set page(height: 40pt);Wide] + +// Flipped predefined paper. +#[#set page(paper: "a11", flipped: true);Flipped A11] + +--- page-set-in-container --- +#box[ + // Error: 4-18 page configuration is not allowed inside of containers + #set page("a4") +] + +--- page-set-empty --- +// Empty with styles +// Should result in one conifer-colored A11 page. +#set page("a11", flipped: true, fill: conifer) + +--- page-set-only-pagebreak --- +// Empty with styles and then pagebreak +// Should result in two forest-colored pages. +#set page(fill: forest) +#pagebreak() + +--- page-set-override-thrice --- +// Empty with multiple page styles. +// Should result in a small white page. +#set page("a4") +#set page("a5") +#set page(width: 1cm, height: 1cm) + +--- page-set-override-and-mix --- +// Empty with multiple page styles. +// Should result in one eastern-colored A11 page. +#set page("a4") +#set page("a5") +#set page("a11", flipped: true, fill: eastern) +#set text(font: "Roboto", white) +#smallcaps[Typst] + +--- page-large --- +#set page("a4") + +--- page-fill --- +// Test page fill. +#set page(width: 80pt, height: 40pt, fill: eastern) +#text(15pt, font: "Roboto", fill: white, smallcaps[Typst]) +#page(width: 40pt, fill: none, margin: (top: 10pt, rest: auto))[Hi] + +--- page-margin-uniform --- +// Set all margins at once. +#[ + #set page(height: 20pt, margin: 5pt) + #place(top + left)[TL] + #place(bottom + right)[BR] +] + +--- page-margin-individual --- +// Set individual margins. +#set page(height: 40pt) +#[#set page(margin: (left: 0pt)); #align(left)[Left]] +#[#set page(margin: (right: 0pt)); #align(right)[Right]] +#[#set page(margin: (top: 0pt)); #align(top)[Top]] +#[#set page(margin: (bottom: 0pt)); #align(bottom)[Bottom]] + +// Ensure that specific margins override general margins. +#[#set page(margin: (rest: 0pt, left: 20pt)); Overridden] + +--- page-margin-inside-outside-override --- +#set page(height: 100pt, margin: (inside: 30pt, outside: 20pt)) +#set par(justify: true) +#set text(size: 8pt) + +#page(margin: (x: 20pt), { + set align(center + horizon) + text(20pt, strong[Title]) + v(2em, weak: true) + text(15pt)[Author] +}) + += Introduction +#lorem(35) + +--- page-margin-inside --- +#set page(margin: (inside: 30pt)) +#rect(width: 100%)[Bound] +#pagebreak() +#rect(width: 100%)[Left] + +--- page-margin-inside-with-binding --- +// Test setting the binding explicitly. +#set page(binding: right, margin: (inside: 30pt)) +#rect(width: 100%)[Bound] +#pagebreak() +#rect(width: 100%)[Right] + +--- page-margin-binding-from-text-lang --- +// Test setting the binding implicitly. +#set page(margin: (inside: 30pt)) +#set text(lang: "he") +#rect(width: 100%)[Bound] +#pagebreak() +#rect(width: 100%)[Right] + +--- page-margin-left-and-outside --- +// Error: 19-44 `inside` and `outside` are mutually exclusive with `left` and `right` +#set page(margin: (left: 1cm, outside: 2cm)) + +--- page-margin-binding-bad --- +// Error: 20-23 must be `left` or `right` +#set page(binding: top) + +--- page-marginals --- +#set page( + paper: "a8", + margin: (x: 15pt, y: 30pt), + header: { + text(eastern)[*Typst*] + h(1fr) + text(0.8em)[_Chapter 1_] + }, + footer: context align(center)[\~ #counter(page).display() \~], + background: context if counter(page).get().first() <= 2 { + place(center + horizon, circle(radius: 1cm, fill: luma(90%))) + } +) + +But, soft! what light through yonder window breaks? It is the east, and Juliet +is the sun. Arise, fair sun, and kill the envious moon, Who is already sick and +pale with grief, That thou her maid art far more fair than she: Be not her maid, +since she is envious; Her vestal livery is but sick and green And none but fools +do wear it; cast it off. It is my lady, O, it is my love! O, that she knew she +were! She speaks yet she says nothing: what of that? Her eye discourses; I will +answer it. + +#set page(header: none, height: auto, margin: (top: 15pt, bottom: 25pt)) +The END. + +--- page-number-align-top-right --- +#set page( + height: 100pt, + margin: 30pt, + numbering: "(1)", + number-align: top + right, +) + +#block(width: 100%, height: 100%, fill: aqua.lighten(50%)) + +--- page-number-align-bottom-left --- +#set page( + height: 100pt, + margin: 30pt, + numbering: "[1]", + number-align: bottom + left, +) + +#block(width: 100%, height: 100%, fill: aqua.lighten(50%)) + +--- page-number-align-left-horizon --- +// Error: 25-39 expected `top` or `bottom`, found horizon +#set page(number-align: left + horizon) + +--- page-numbering-pdf-label --- +#set page(margin: (bottom: 20pt, rest: 10pt)) +#let filler = lorem(20) + +// (i) - (ii). No style opt. because of suffix. +#set page(numbering: "(i)") +#filler +#pagebreak() +#filler + +// 3 - 4. Style opt. Page Label should use /D style. +#set page(numbering: "1") +#filler +#pagebreak() +#filler + +// I - IV. Style opt. Page Label should use /R style and start at 1 again. +#set page(numbering: "I / I") +#counter(page).update(1) +#filler +#pagebreak() +#filler +#pagebreak() +#filler +#pagebreak() +#filler + +// Pre: ほ, Pre: ろ, Pre: は, Pre: に. No style opt. Uses prefix field entirely. +// Counter update without numbering change. +#set page(numbering: "Pre: い") +#filler +#pagebreak() +#filler +#counter(page).update(2) +#filler +#pagebreak() +#filler +#pagebreak() +#filler + +// aa & ba. Style opt only for values <= 26. Page Label uses lower alphabet style. +// Repeats letter each 26 pages or uses numbering directly as prefix. +#set page(numbering: "a") +#counter(page).update(27) +#filler +#pagebreak() +#counter(page).update(53) +#filler diff --git a/tests/suite/layout/pagebreak.typ b/tests/suite/layout/pagebreak.typ new file mode 100644 index 00000000..a1734596 --- /dev/null +++ b/tests/suite/layout/pagebreak.typ @@ -0,0 +1,143 @@ +// Test forced page breaks. + +--- pagebreak --- +// Just a pagebreak. +// Should result in two pages. +#pagebreak() + +--- pagebreak-around-set-page --- +// Pagebreak, empty with styles and then pagebreak +// Should result in one auto-sized page and two conifer-colored 2cm wide pages. +#pagebreak() +#set page(width: 2cm, fill: conifer) +#pagebreak() + +--- pagebreak-weak-after-set-page --- +// Two text bodies separated with and surrounded by weak pagebreaks. +// Should result in two aqua-colored pages. +#set page(fill: aqua) +#pagebreak(weak: true) +First +#pagebreak(weak: true) +Second +#pagebreak(weak: true) + +--- pagebreak-set-page-mixed --- +// Test a combination of pagebreaks, styled pages and pages with bodies. +// Should result in three five pages, with the fourth one being forest-colored. +#set page(width: 80pt, height: 30pt) +#[#set page(width: 60pt); First] +#pagebreak() +#pagebreak() +Third +#page(height: 20pt, fill: forest)[] +Fif#[#set page();th] + +--- pagebreak-followed-by-page-call --- +// Test hard and weak pagebreak followed by page with body. +// Should result in three navy-colored pages. +#set page(fill: navy) +#set text(fill: white) +First +#pagebreak() +#page[Second] +#pagebreak(weak: true) +#page[Third] + +--- pagebreak-in-container --- +#box[ + // Error: 4-15 pagebreaks are not allowed inside of containers + #pagebreak() +] + +--- pagebreak-weak-place --- +// After place +// Should result in three pages. +First +#pagebreak(weak: true) +#place(right)[placed A] +#pagebreak(weak: true) +Third + +--- pagebreak-weak-meta --- +// After only ignorables & invisibles +// Should result in two pages. +First +#pagebreak(weak: true) +#counter(page).update(1) +#metadata("Some") +#pagebreak(weak: true) +Second + +--- pagebreak-meta --- +// After only ignorables, but regular break +// Should result in three pages. +First +#pagebreak() +#counter(page).update(1) +#metadata("Some") +#pagebreak() +Third + +--- pagebreak-to --- +#set page(width: 80pt, height: 30pt) +First +#pagebreak(to: "odd") +Third +#pagebreak(to: "even") +Fourth +#pagebreak(to: "even") +Sixth +#pagebreak() +Seventh +#pagebreak(to: "odd") +#page[Ninth] + +--- pagebreak-to-auto-sized --- +#set page(width: auto, height: auto) + +// Test with auto-sized page. +First +#pagebreak(to: "odd") +Third + +--- pagebreak-to-multiple-pages --- +#set page(height: 30pt, width: 80pt) + +// Test when content extends to more than one page +First + +Second + +#pagebreak(to: "odd") + +Third + +--- issue-2134-pagebreak-bibliography --- +// Test weak pagebreak before bibliography. +#pagebreak(weak: true) +#bibliography("/assets/bib/works.bib") + +--- issue-2095-pagebreak-numbering --- +// The empty page 2 should not have a page number +#set page(numbering: none) +This and next page should not be numbered + +#pagebreak(weak: true, to: "odd") + +#set page(numbering: "1") +#counter(page).update(1) + +This page should + +--- issue-2162-pagebreak-set-style --- +// The styles should not be applied to the pagebreak empty page, +// it should only be applied after that. +#pagebreak(to: "even") // We should now skip to page 2 + +Some text on page 2 + +#pagebreak(to: "even") // We should now skip to page 4 + +#set page(fill: orange) // This sets the color of the page starting from page 4 +Some text on page 4 diff --git a/tests/suite/layout/place.typ b/tests/suite/layout/place.typ new file mode 100644 index 00000000..b8765e93 --- /dev/null +++ b/tests/suite/layout/place.typ @@ -0,0 +1,226 @@ +// Test the `place` function. + +--- place-basic --- +#set page("a8") +#place(bottom + center)[© Typst] + += Placement +#place(right, image("/assets/images/tiger.jpg", width: 1.8cm)) +Hi there. This is \ +a placed element. \ +Unfortunately, \ +the line breaks still had to be inserted manually. + +#stack( + rect(fill: eastern, height: 10pt, width: 100%), + place(right, dy: 1.5pt)[ABC], + rect(fill: conifer, height: 10pt, width: 80%), + rect(fill: forest, height: 10pt, width: 100%), + 10pt, + block[ + #place(center, dx: -7pt, dy: -5pt)[Hello] + #place(center, dx: 7pt, dy: 5pt)[Hello] + Hello #h(1fr) Hello + ] +) + +--- place-block-spacing --- +// Test how the placed element interacts with paragraph spacing around it. +#set page("a8", height: 60pt) + +First + +#place(bottom + right)[Placed] + +Second + +--- place-background --- +#set page(paper: "a10", flipped: true) +#set text(fill: white) +#place( + dx: -10pt, + dy: -10pt, + image( + "/assets/images/tiger.jpg", + fit: "cover", + width: 100% + 20pt, + height: 100% + 20pt, + ) +) +#align(bottom + right)[ + _Welcome to_ #underline[*Tigerland*] +] + +--- place-float --- +#set page(height: 140pt) +#set place(clearance: 5pt) +#lorem(6) +#place(auto, float: true, rect[A]) +#place(auto, float: true, rect[B]) +#place(auto, float: true, rect[C]) +#place(auto, float: true, rect[D]) + +--- place-float-missing --- +// Error: 2-20 automatic positioning is only available for floating placement +// Hint: 2-20 you can enable floating placement with `place(float: true, ..)` +#place(auto)[Hello] + +--- place-float-center-horizon --- +// Error: 2-45 floating placement must be `auto`, `top`, or `bottom` +#place(center + horizon, float: true)[Hello] + +--- place-float-horizon --- +// Error: 2-36 floating placement must be `auto`, `top`, or `bottom` +#place(horizon, float: true)[Hello] + +--- place-float-default --- +// Error: 2-27 floating placement must be `auto`, `top`, or `bottom` +#place(float: true)[Hello] + +--- place-float-right --- +// Error: 2-34 floating placement must be `auto`, `top`, or `bottom` +#place(right, float: true)[Hello] + +--- place-float-columns --- +// LARGE +#set page(height: 200pt, width: 300pt) +#show: columns.with(2) + += Introduction +#figure( + placement: bottom, + caption: [A glacier], + image("/assets/images/glacier.jpg", width: 50%), +) +#lorem(45) +#figure( + placement: top, + caption: [A rectangle], + rect[Hello!], +) +#lorem(20) + +--- place-float-figure --- +// LARGE +#set page(height: 250pt, width: 150pt) + += Introduction +#lorem(10) #footnote[Lots of Latin] + +#figure( + placement: bottom, + caption: [A glacier #footnote[Lots of Ice]], + image("/assets/images/glacier.jpg", width: 80%), +) + +#lorem(40) + +#figure( + placement: top, + caption: [An important], + image("/assets/images/diagram.svg", width: 80%), +) + +--- place-bottom-in-box --- +#box( + fill: aqua, + width: 30pt, + height: 30pt, + place(bottom, + place(line(start: (0pt, 0pt), end: (20pt, 0pt), stroke: red + 3pt)) + ) +) + +--- place-horizon-in-boxes --- +#box( + fill: aqua, + width: 30pt, + height: 30pt, + { + box(fill: yellow, { + [Hello] + place(horizon, line(start: (0pt, 0pt), end: (20pt, 0pt), stroke: red + 2pt)) + }) + place(horizon, line(start: (0pt, 0pt), end: (20pt, 0pt), stroke: green + 3pt)) + } +) + +--- place-bottom-right-in-box --- +#box(fill: aqua)[ + #place(bottom + right)[Hi] + Hello World \ + How are \ + you? +] + +--- place-top-left-in-box --- +#box(fill: aqua)[ + #place(top + left, dx: 50%, dy: 50%)[Hi] + #v(30pt) + #line(length: 50pt) +] + +--- issue-place-base --- +// Test that placement is relative to container and not itself. +#set page(height: 80pt, margin: 0pt) +#place(right, dx: -70%, dy: 20%, [First]) +#place(left, dx: 20%, dy: 60%, [Second]) +#place(center + horizon, dx: 25%, dy: 25%, [Third]) + +--- issue-1368-place-pagebreak --- +// Test placing on an already full page. +// It shouldn't result in a page break. +#set page(height: 40pt) +#block(height: 100%) +#place(bottom + right)[Hello world] + +--- issue-2199-place-spacing-bottom --- +// Test that placed elements don't add extra block spacing. +#show figure: set block(spacing: 4em) + +Paragraph before float. +#figure(rect(), placement: bottom) +Paragraph after float. + +--- issue-2199-place-spacing-default --- +#show place: set block(spacing: 4em) + +Paragraph before place. +#place(rect()) +Paragraph after place. + +--- issue-2595-float-overlap --- +#set page(height: 80pt) + +Start. + +#place(auto, float: true, [ + #block(height: 100%, width: 100%, fill: aqua) +]) + +#place(auto, float: true, [ + #block(height: 100%, width: 100%, fill: red) +]) + +#lorem(20) + +--- issue-2715-float-order --- +#set page(height: 180pt) +#set figure(placement: auto) + +#figure( + rect(height: 60pt), + caption: [Rectangle I], +) + +#figure( + rect(height: 50pt), + caption: [Rectangle II], +) + +#figure( + circle(), + caption: [Circle], +) + +#lorem(20) diff --git a/tests/suite/layout/relative.typ b/tests/suite/layout/relative.typ new file mode 100644 index 00000000..958aee3d --- /dev/null +++ b/tests/suite/layout/relative.typ @@ -0,0 +1,7 @@ +--- relative-fields --- +// Test relative length fields. +#test((100% + 2em + 2pt).ratio, 100%) +#test((100% + 2em + 2pt).length, 2em + 2pt) +#test((100% + 2pt).length, 2pt) +#test((100% + 2pt - 2pt).length, 0pt) +#test((56% + 2pt - 56%).ratio, 0%) diff --git a/tests/suite/layout/repeat.typ b/tests/suite/layout/repeat.typ new file mode 100644 index 00000000..5c82fc19 --- /dev/null +++ b/tests/suite/layout/repeat.typ @@ -0,0 +1,44 @@ +// Test the `repeat` function. + +--- repeat-basic --- +// Test multiple repeats. +#let sections = ( + ("Introduction", 1), + ("Approach", 1), + ("Evaluation", 3), + ("Discussion", 15), + ("Related Work", 16), + ("Conclusion", 253), +) + +#for section in sections [ + #section.at(0) #box(width: 1fr, repeat[.]) #section.at(1) \ +] + +--- repeat-dots-rtl --- +// Test dots with RTL. +#set text(lang: "ar") +مقدمة #box(width: 1fr, repeat[.]) 15 + +--- repeat-empty --- +// Test empty repeat. +A #box(width: 1fr, repeat[]) B + +--- repeat-unboxed --- +// Test unboxed repeat. +#repeat(rect(width: 2em, height: 1em)) + +--- repeat-align-and-dir --- +// Test single repeat in both directions. +A#box(width: 1fr, repeat(rect(width: 6em, height: 0.7em)))B + +#set align(center) +A#box(width: 1fr, repeat(rect(width: 6em, height: 0.7em)))B + +#set text(dir: rtl) +ريجين#box(width: 1fr, repeat(rect(width: 4em, height: 0.7em)))سون + +--- repeat-unrestricted --- +// Error: 2:2-2:13 repeat with no size restrictions +#set page(width: auto) +#repeat(".") diff --git a/tests/suite/layout/spacing.typ b/tests/suite/layout/spacing.typ new file mode 100644 index 00000000..430e9779 --- /dev/null +++ b/tests/suite/layout/spacing.typ @@ -0,0 +1,38 @@ +// Test the `h` and `v` functions. + +--- spacing-h-and-v --- +// Linebreak and leading-sized weak spacing are equivalent. +#box[A \ B] #box[A #v(0.65em, weak: true) B] + +// Eating up soft spacing. +Inv#h(0pt)isible + +// Multiple spacings in a row. +Add #h(10pt) #h(10pt) up + +// Relative to area. +#let x = 25% - 4pt +|#h(x)|#h(x)|#h(x)|#h(x)| + +// Fractional. +| #h(1fr) | #h(2fr) | #h(1fr) | + +--- spacing-rtl --- +// Test RTL spacing. +#set text(dir: rtl) +A #h(10pt) B \ +A #h(1fr) B + +--- spacing-missing-amount --- +// Missing spacing. +// Error: 10-13 missing argument: amount +Totally #h() ignored + +--- issue-3624-spacing-behaviour --- +// Test that metadata after spacing does not force a new paragraph. +#{ + h(1em) + counter(heading).update(4) + [Hello ] + counter(heading).display() +} diff --git a/tests/suite/layout/stack.typ b/tests/suite/layout/stack.typ new file mode 100644 index 00000000..1eca52c9 --- /dev/null +++ b/tests/suite/layout/stack.typ @@ -0,0 +1,82 @@ +// Test stack layouts. + +--- stack-basic --- +// Test stacks with different directions. +#let widths = ( + 30pt, 20pt, 40pt, 15pt, + 30pt, 50%, 20pt, 100%, +) + +#let shaded(i, w) = { + let v = (i + 1) * 10% + rect(width: w, height: 10pt, fill: rgb(v, v, v)) +} + +#let items = for (i, w) in widths.enumerate() { + (align(right, shaded(i, w)),) +} + +#set page(width: 50pt, margin: 0pt) +#stack(dir: btt, ..items) + +--- stack-spacing --- +// Test spacing. +#set page(width: 50pt, margin: 0pt) + +#let x = square(size: 10pt, fill: eastern) +#stack( + spacing: 5pt, + stack(dir: rtl, spacing: 5pt, x, x, x), + stack(dir: ltr, x, 20%, x, 20%, x), + stack(dir: ltr, spacing: 5pt, x, x, 7pt, 3pt, x), +) + +--- stack-overflow --- +// Test overflow. +#set page(width: 50pt, height: 30pt, margin: 0pt) +#box(stack( + rect(width: 40pt, height: 20pt, fill: conifer), + rect(width: 30pt, height: 13pt, fill: forest), +)) + +--- stack-fr --- +#set page(height: 3.5cm) +#stack( + dir: ltr, + spacing: 1fr, + ..for c in "ABCDEFGHI" {([#c],)} +) + +Hello +#v(2fr) +from #h(1fr) the #h(1fr) wonderful +#v(1fr) +World! 🌍 + +--- stack-rtl-align-and-fr --- +// Test aligning things in RTL stack with align function & fr units. +#set page(width: 50pt, margin: 5pt) +#set block(spacing: 5pt) +#set text(8pt) +#stack(dir: rtl, 1fr, [A], 1fr, [B], [C]) +#stack(dir: rtl, + align(center, [A]), + align(left, [B]), + [C], +) + +--- issue-1240-stack-h-fr --- +// This issue is sort of horrible: When you write `h(1fr)` in a `stack` instead +// of directly `1fr`, things go awry. To fix this, we now transparently detect +// h/v children. +#stack(dir: ltr, [a], 1fr, [b], 1fr, [c]) +#stack(dir: ltr, [a], h(1fr), [b], h(1fr), [c]) + +--- issue-1240-stack-v-fr --- +#set page(height: 60pt) +#stack( + dir: ltr, + spacing: 1fr, + stack([a], 1fr, [b]), + stack([a], v(1fr), [b]), +) diff --git a/tests/suite/layout/table.typ b/tests/suite/layout/table.typ new file mode 100644 index 00000000..7eec46a1 --- /dev/null +++ b/tests/suite/layout/table.typ @@ -0,0 +1,284 @@ +// Test tables. + +--- table-empty --- +#table() + +--- table-newlines --- +#set page(height: 70pt) +#set table(fill: (x, y) => if calc.even(x + y) { rgb("aaa") }) + +#table( + columns: (1fr,) * 3, + stroke: 2pt + rgb("333"), + [A], [B], [C], [], [], [D \ E \ F \ \ \ G], [H], +) + +--- table-fill-basic --- +#table(columns: 3, stroke: none, fill: green, [A], [B], [C]) + +--- table-fill-bad --- +// Error: 14-19 expected color, gradient, pattern, none, array, or function, found string +#table(fill: "hey") + +--- table-align-array --- +// Test alignment with array. +#table( + columns: (1fr, 1fr, 1fr), + align: (left, center, right), + [A], [B], [C] +) + +// Test empty array. +#set align(center) +#table( + columns: (1fr, 1fr, 1fr), + align: (), + [A], [B], [C] +) + +--- table-inset --- +// Test inset. +#table( + columns: 3, + inset: 10pt, + [A], [B], [C] +) + +#table( + columns: 3, + inset: (y: 10pt), + [A], [B], [C] +) + +#table( + columns: 3, + inset: (left: 20pt, rest: 10pt), + [A], [B], [C] +) + +#table( + columns: 2, + inset: ( + left: 20pt, + right: 5pt, + top: 10pt, + bottom: 3pt, + ), + [A], + [B], +) + +#table( + columns: 3, + fill: (x, y) => (if y == 0 { aqua } else { orange }).darken(x * 15%), + inset: (x, y) => (left: if x == 0 { 0pt } else { 5pt }, right: if x == 0 { 5pt } else { 0pt }, y: if y == 0 { 0pt } else { 5pt }), + [A], [B], [C], + [A], [B], [C], +) + +#table( + columns: 3, + inset: (0pt, 5pt, 10pt), + fill: (x, _) => aqua.darken(x * 15%), + [A], [B], [C], +) + +--- table-inset-fold --- +// Test inset folding +#set table(inset: 10pt) +#set table(inset: (left: 0pt)) + +#table( + fill: red, + inset: (right: 0pt), + table.cell(inset: (top: 0pt))[a] +) + +--- table-gutters --- +// Test interaction with gutters. +#table( + columns: (3em, 3em), + fill: (x, y) => (red, blue).at(calc.rem(x, 2)), + align: (x, y) => (left, right).at(calc.rem(y, 2)), + [A], [B], + [C], [D], + [E], [F], + [G], [H] +) + +#table( + columns: (3em, 3em), + fill: (x, y) => (red, blue).at(calc.rem(x, 2)), + align: (x, y) => (left, right).at(calc.rem(y, 2)), + row-gutter: 5pt, + [A], [B], + [C], [D], + [E], [F], + [G], [H] +) + +#table( + columns: (3em, 3em), + fill: (x, y) => (red, blue).at(calc.rem(x, 2)), + align: (x, y) => (left, right).at(calc.rem(y, 2)), + column-gutter: 5pt, + [A], [B], + [C], [D], + [E], [F], + [G], [H] +) + +#table( + columns: (3em, 3em), + fill: (x, y) => (red, blue).at(calc.rem(x, 2)), + align: (x, y) => (left, right).at(calc.rem(y, 2)), + gutter: 5pt, + [A], [B], + [C], [D], + [E], [F], + [G], [H] +) + +--- table-cell-override --- +// Cell override +#table( + align: left, + fill: red, + stroke: blue, + columns: 2, + [AAAAA], [BBBBB], + [A], [B], + table.cell(align: right)[C], [D], + align(right)[E], [F], + align(horizon)[G], [A\ A\ A], + table.cell(align: horizon)[G2], [A\ A\ A], + table.cell(inset: 0pt)[I], [F], + [H], table.cell(fill: blue)[J] +) + +--- table-cell-show --- +// Cell show rule +#show table.cell: it => [Zz] + +#table( + align: left, + fill: red, + stroke: blue, + columns: 2, + [AAAAA], [BBBBB], + [A], [B], + table.cell(align: right)[C], [D], + align(right)[E], [F], + align(horizon)[G], [A\ A\ A] +) + +--- table-cell-show-and-override --- +#show table.cell: it => (it.align, it.fill) +#table( + align: left, + row-gutter: 5pt, + [A], + table.cell(align: right)[B], + table.cell(fill: aqua)[B], +) + +--- table-cell-set --- +// Cell set rules +#set table.cell(align: center) +#show table.cell: it => (it.align, it.fill, it.inset) +#set table.cell(inset: 20pt) +#table( + align: left, + row-gutter: 5pt, + [A], + table.cell(align: right)[B], + table.cell(fill: aqua)[B], +) + +--- table-cell-folding --- +// Test folding per-cell properties (align and inset) +#table( + columns: (1fr, 1fr), + rows: (2.5em, auto), + align: right, + fill: (x, y) => (green, aqua).at(calc.rem(x + y, 2)), + [Top], table.cell(align: bottom)[Bot], + table.cell(inset: (bottom: 0pt))[Bot], table.cell(inset: (bottom: 0pt))[Bot] +) + +--- table-cell-align-override --- +// Test overriding outside alignment +#set align(bottom + right) +#table( + columns: (1fr, 1fr), + rows: 2em, + align: auto, + fill: green, + [BR], [BR], + table.cell(align: left, fill: aqua)[BL], table.cell(align: top, fill: red.lighten(50%))[TR] +) + +--- table-cell-various-overrides --- +#table( + columns: 2, + fill: green, + align: right, + [*Name*], [*Data*], + table.cell(fill: blue)[J.], [Organizer], + table.cell(align: center)[K.], [Leader], + [M.], table.cell(inset: 0pt)[Player] +) + +--- table-cell-show-emph --- +#{ + show table.cell: emph + table( + columns: 2, + [Person], [Animal], + [John], [Dog] + ) +} + +--- table-cell-show-based-on-position --- +// Style based on position +#{ + show table.cell: it => { + if it.y == 0 { + strong(it) + } else if it.x == 1 { + emph(it) + } else { + it + } + } + table( + columns: 3, + gutter: 3pt, + [Name], [Age], [Info], + [John], [52], [Nice], + [Mary], [50], [Cool], + [Jake], [49], [Epic] + ) +} + +--- grid-cell-in-table --- +// Error: 8-19 cannot use `grid.cell` as a table cell; use `table.cell` instead +#table(grid.cell[]) + +--- issue-183-table-lines --- +// Ensure no empty lines before a table that doesn't fit into the first page. +#set page(height: 50pt) + +Hello +#table( + columns: 4, + [1], [2], [3], [4] +) + +--- issue-1388-table-row-missing --- +// Test that a table row isn't wrongly treated like a gutter row. +#set page(height: 70pt) +#table( + rows: 16pt, + ..range(6).map(str).flatten(), +) diff --git a/tests/suite/layout/transform.typ b/tests/suite/layout/transform.typ new file mode 100644 index 00000000..50a6d417 --- /dev/null +++ b/tests/suite/layout/transform.typ @@ -0,0 +1,106 @@ +// Test transformations. + +--- transform-tex-logo --- +// Test creating the TeX and XeTeX logos. +#let size = 11pt +#let tex = { + [T] + h(-0.14 * size) + box(move(dy: 0.22 * size)[E]) + h(-0.12 * size) + [X] +} + +#let xetex = { + [X] + h(-0.14 * size) + box(scale(x: -100%, move(dy: 0.26 * size)[E])) + h(-0.14 * size) + [T] + h(-0.14 * size) + box(move(dy: 0.26 * size)[E]) + h(-0.12 * size) + [X] +} + +#set text(font: "New Computer Modern", size) +Neither #tex, \ +nor #xetex! + +--- transform-rotate-and-scale --- +// Test combination of scaling and rotation. +#set page(height: 80pt) +#align(center + horizon, + rotate(20deg, scale(70%, image("/assets/images/tiger.jpg"))) +) + +--- transform-rotate-origin --- +// Test setting rotation origin. +#rotate(10deg, origin: top + left, + image("/assets/images/tiger.jpg", width: 50%) +) + +--- transform-scale-origin --- +// Test setting scaling origin. +#let r = rect(width: 100pt, height: 10pt, fill: forest) +#set page(height: 65pt) +#box(scale(r, x: 50%, y: 200%, origin: left + top)) +#box(scale(r, x: 50%, origin: center)) +#box(scale(r, x: 50%, y: 200%, origin: right + bottom)) + +--- transform-rotate --- +// Test that rotation impact layout. +#set page(width: 200pt) +#set rotate(reflow: true) + +#let one(angle) = box(fill: aqua, rotate(angle)[Test Text]) +#for angle in range(0, 360, step: 15) { + one(angle * 1deg) +} + +--- transform-rotate-relative-sizing --- +// Test relative sizing in rotated boxes. +#set page(width: 200pt, height: 200pt) +#set text(size: 32pt) +#let rotated(body) = box(rotate( + 90deg, + box(stroke: 0.5pt, height: 20%, clip: true, body) +)) + +#set rotate(reflow: false) +Hello #rotated[World]!\ + +#set rotate(reflow: true) +Hello #rotated[World]! + +--- transform-scale --- +// Test that scaling impact layout. +#set page(width: 200pt) +#set text(size: 32pt) +#let scaled(body) = box(scale( + x: 20%, + y: 40%, + body +)) + +#set scale(reflow: false) +Hello #scaled[World]! + +#set scale(reflow: true) +Hello #scaled[World]! + +--- transform-scale-relative-sizing --- +// Test relative sizing in scaled boxes. +#set page(width: 200pt, height: 200pt) +#set text(size: 32pt) +#let scaled(body) = box(scale( + x: 60%, + y: 40%, + box(stroke: 0.5pt, width: 30%, clip: true, body) +)) + +#set scale(reflow: false) +Hello #scaled[World]!\ + +#set scale(reflow: true) +Hello #scaled[World]! diff --git a/tests/suite/loading/csv.typ b/tests/suite/loading/csv.typ new file mode 100644 index 00000000..415488fc --- /dev/null +++ b/tests/suite/loading/csv.typ @@ -0,0 +1,27 @@ +--- csv --- +// Test reading CSV data. +#set page(width: auto) +#let data = csv("/assets/data/zoo.csv") +#let cells = data.at(0).map(strong) + data.slice(1).flatten() +#table(columns: data.at(0).len(), ..cells) + +--- csv-row-type-dict --- +// Test reading CSV data with dictionary rows enabled. +#let data = csv("/assets/data/zoo.csv", row-type: dictionary) +#test(data.len(), 3) +#test(data.at(0).Name, "Debby") +#test(data.at(2).Weight, "150kg") +#test(data.at(1).Species, "Tiger") + +--- csv-file-not-found --- +// Error: 6-16 file not found (searched at tests/suite/loading/nope.csv) +#csv("nope.csv") + +--- csv-invalid --- +// Error: 6-28 failed to parse CSV (found 3 instead of 2 fields in line 3) +#csv("/assets/data/bad.csv") + +--- csv-invalid-row-type-dict --- +// Test error numbering with dictionary rows. +// Error: 6-28 failed to parse CSV (found 3 instead of 2 fields in line 3) +#csv("/assets/data/bad.csv", row-type: dictionary) diff --git a/tests/suite/loading/json.typ b/tests/suite/loading/json.typ new file mode 100644 index 00000000..3ebeaf2f --- /dev/null +++ b/tests/suite/loading/json.typ @@ -0,0 +1,16 @@ +--- json --- +// Test reading JSON data. +#let data = json("/assets/data/zoo.json") +#test(data.len(), 3) +#test(data.at(0).name, "Debby") +#test(data.at(2).weight, 150) + +--- json-invalid --- +// Error: 7-30 failed to parse JSON (expected value at line 3 column 14) +#json("/assets/data/bad.json") + +--- issue-3363-json-large-number --- +// Big numbers (larger than what i64 can store) should just lose some precision +// but not overflow +#let bignum = json("/assets/data/big-number.json") +#bignum diff --git a/tests/suite/loading/read.typ b/tests/suite/loading/read.typ new file mode 100644 index 00000000..b5c9c089 --- /dev/null +++ b/tests/suite/loading/read.typ @@ -0,0 +1,12 @@ +--- read-text --- +// Test reading plain text files +#let data = read("/assets/text/hello.txt") +#test(data, "Hello, world!\n") + +--- read-file-not-found --- +// Error: 18-44 file not found (searched at assets/text/missing.txt) +#let data = read("/assets/text/missing.txt") + +--- read-invalid-utf-8 --- +// Error: 18-40 file is not valid utf-8 +#let data = read("/assets/text/bad.txt") diff --git a/tests/suite/loading/toml.typ b/tests/suite/loading/toml.typ new file mode 100644 index 00000000..855ca995 --- /dev/null +++ b/tests/suite/loading/toml.typ @@ -0,0 +1,41 @@ +--- toml --- +// Test reading TOML data. +#let data = toml("/assets/data/toml-types.toml") +#test(data.string, "wonderful") +#test(data.integer, 42) +#test(data.float, 3.14) +#test(data.boolean, true) +#test(data.array, (1, "string", 3.0, false)) +#test(data.inline_table, ("first": "amazing", "second": "greater") ) +#test(data.table.element, 5) +#test(data.table.others, (false, "indeed", 7)) +#test(data.date_time, datetime( + year: 2023, + month: 2, + day: 1, + hour: 15, + minute: 38, + second: 57, +)) +#test(data.date_time2, datetime( + year: 2023, + month: 2, + day: 1, + hour: 15, + minute: 38, + second: 57, +)) +#test(data.date, datetime( + year: 2023, + month: 2, + day: 1, +)) +#test(data.time, datetime( + hour: 15, + minute: 38, + second: 57, +)) + +--- toml-invalid --- +// Error: 7-30 failed to parse TOML (expected `.`, `=` at line 1 column 16) +#toml("/assets/data/bad.toml") diff --git a/tests/suite/loading/xml.typ b/tests/suite/loading/xml.typ new file mode 100644 index 00000000..41cd20e7 --- /dev/null +++ b/tests/suite/loading/xml.typ @@ -0,0 +1,28 @@ +--- xml --- +// Test reading XML data. +#let data = xml("/assets/data/hello.xml") +#test(data, (( + tag: "data", + attrs: (:), + children: ( + "\n ", + (tag: "hello", attrs: (name: "hi"), children: ("1",)), + "\n ", + ( + tag: "data", + attrs: (:), + children: ( + "\n ", + (tag: "hello", attrs: (:), children: ("World",)), + "\n ", + (tag: "hello", attrs: (:), children: ("World",)), + "\n ", + ), + ), + "\n", + ), +),)) + +--- xml-invalid --- +// Error: 6-28 failed to parse XML (found closing tag 'data' instead of 'hello' in line 3) +#xml("/assets/data/bad.xml") diff --git a/tests/suite/loading/yaml.typ b/tests/suite/loading/yaml.typ new file mode 100644 index 00000000..bbfea41c --- /dev/null +++ b/tests/suite/loading/yaml.typ @@ -0,0 +1,17 @@ +--- yaml --- +// Test reading YAML data +#let data = yaml("/assets/data/yaml-types.yaml") +#test(data.len(), 9) +#test(data.null_key, (none, none)) +#test(data.string, "text") +#test(data.integer, 5) +#test(data.float, 1.12) +#test(data.mapping, ("1": "one", "2": "two")) +#test(data.seq, (1,2,3,4)) +#test(data.bool, false) +#test(data.keys().contains("true"), true) +#test(data.at("1"), "ok") + +--- yaml-invalid --- +// Error: 7-30 failed to parse YAML (did not find expected ',' or ']' at line 2 column 1, while parsing a flow sequence at line 1 column 18) +#yaml("/assets/data/bad.yaml") diff --git a/tests/suite/math/accent.typ b/tests/suite/math/accent.typ new file mode 100644 index 00000000..9f57d69b --- /dev/null +++ b/tests/suite/math/accent.typ @@ -0,0 +1,33 @@ +// Test math accents. + +--- math-accent-sym-call --- +// Test function call. +$grave(a), acute(b), hat(f), tilde(§), macron(ä), diaer(a), ä \ + breve(\&), dot(!), circle(a), caron(@), arrow(Z), arrow.l(Z)$ + +--- math-accent-align --- +$ x &= p \ dot(x) &= v \ dot.double(x) &= a \ dot.triple(x) &= j \ dot.quad(x) &= s $ + +--- math-accent-func --- +// Test `accent` function. +$accent(ö, .), accent(v, <-), accent(ZZ, \u{0303})$ + +--- math-accent-bounds --- +// Test accent bounds. +$sqrt(tilde(T)) + hat(f)/hat(g)$ + +--- math-accent-wide-base --- +// Test wide base. +$arrow("ABC" + d), tilde(sum)$ + +--- math-accent-superscript --- +// Test effect of accent on superscript. +$A^x != hat(A)^x != hat(hat(A))^x$ + +--- math-accent-high-base --- +// Test high base. +$ tilde(integral), tilde(integral)_a^b, tilde(integral_a^b) $ + +--- math-accent-sized --- +// Test accent size. +$tilde(sum), tilde(sum, size: #50%), accent(H, hat, size: #200%)$ diff --git a/tests/suite/math/alignment.typ b/tests/suite/math/alignment.typ new file mode 100644 index 00000000..f110b139 --- /dev/null +++ b/tests/suite/math/alignment.typ @@ -0,0 +1,34 @@ +// Test implicit alignment math. + +--- math-align-weird --- +// Test alignment step functions. +#set page(width: 225pt) +$ +"a" &= c \ +&= c + 1 & "By definition" \ +&= d + 100 + 1000 \ +&= x && "Even longer" \ +$ + +--- math-align-post-fix --- +// Test post-fix alignment. +$ +& "right" \ +"a very long line" \ +"left" \ +$ + +--- math-align-implicit --- +// Test no alignment. +$ +"right" \ +"a very long line" \ +"left" \ +$ + +--- math-align-toggle --- +// Test #460 equations. +$ +a &=b & quad c&=d \ +e &=f & g&=h +$ diff --git a/tests/suite/math/attach.typ b/tests/suite/math/attach.typ new file mode 100644 index 00000000..c9510c6a --- /dev/null +++ b/tests/suite/math/attach.typ @@ -0,0 +1,130 @@ +// Test t and b attachments, part 1. + +--- math-attach-postscripts --- +// Test basics, postscripts. +$f_x + t^b + V_1^2 + attach(A, t: alpha, b: beta)$ + +--- math-attach-prescripts --- +// Test basics, prescripts. Notably, the upper and lower prescripts' content need to be +// aligned on the right edge of their bounding boxes, not on the left as in postscripts. +$ +attach(upright(O), bl: 8, tl: 16, br: 2, tr: 2-), +attach("Pb", bl: 82, tl: 207) + attach(upright(e), bl: -1, tl: 0) + macron(v)_e \ +$ + +--- math-attach-mixed --- +// A mixture of attachment positioning schemes. +$ +attach(a, tl: u), attach(a, tr: v), attach(a, bl: x), +attach(a, br: y), limits(a)^t, limits(a)_b \ + +attach(a, tr: v, t: t), +attach(a, tr: v, br: y), +attach(a, br: y, b: b), +attach(limits(a), b: b, bl: x), +attach(a, tl: u, bl: x), +attach(limits(a), t: t, tl: u) \ + +attach(a, tl: u, tr: v), +attach(limits(a), t: t, br: y), +attach(limits(a), b: b, tr: v), +attach(a, bl: x, br: y), +attach(limits(a), b: b, tl: u), +attach(limits(a), t: t, bl: u), +limits(a)^t_b \ + +attach(a, tl: u, tr: v, bl: x, br: y), +attach(limits(a), t: t, bl: x, br: y, b: b), +attach(limits(a), t: t, tl: u, tr: v, b: b), +attach(limits(a), tl: u, bl: x, t: t, b: b), +attach(limits(a), t: t, b: b, tr: v, br: y), +attach(a, tl: u, t: t, tr: v, bl: x, b: b, br: y) +$ + +--- math-attach-followed-by-func-call --- +// Test function call after subscript. +$pi_1(Y), a_f(x), a^zeta (x), a^abs(b)_sqrt(c) \ + a^subset.eq (x), a_(zeta(x)), pi_(1(Y)), a^(abs(b))_(sqrt(c))$ + +--- math-attach-nested --- +// Test associativity and scaling. +$ 1/(V^2^3^4^5), + frac( + attach( + limits(V), br: attach(2, br: 3), b: attach(limits(2), b: 3)), + attach( + limits(V), tl: attach(2, tl: 3), t: attach(limits(2), t: 3))), + attach(Omega, + tl: attach(2, tl: attach(3, tl: attach(4, tl: 5))), + tr: attach(2, tr: attach(3, tr: attach(4, tr: 5))), + bl: attach(2, bl: attach(3, bl: attach(4, bl: 5))), + br: attach(2, br: attach(3, br: attach(4, br: 5))), + ) +$ + +--- math-attach-high --- +// Test high subscript and superscript. +$ sqrt(a_(1/2)^zeta), sqrt(a_alpha^(1/2)), sqrt(a_(1/2)^(3/4)) \ + sqrt(attach(a, tl: 1/2, bl: 3/4)), + sqrt(attach(a, tl: 1/2, bl: 3/4, tr: 1/2, br: 3/4)) $ + +--- math-attach-descender-collision --- +// Test for no collisions between descenders/ascenders and attachments + +$ sup_(x in P_i) quad inf_(x in P_i) $ +$ op("fff",limits: #true)^(y) quad op("yyy", limits:#true)_(f) $ + +--- math-attach-to-group --- +// Test frame base. +$ (-1)^n + (1/2 + 3)^(-1/2) $ + +--- math-attach-horizontal-align --- +#set text(size: 8pt) + +// Test that the attachments are aligned horizontally. +$ x_1 p_1 frak(p)_1 2_1 dot_1 lg_1 !_1 \\_1 ]_1 "ip"_1 op("iq")_1 \ + x^1 b^1 frak(b)^1 2^1 dot^1 lg^1 !^1 \\^1 ]^1 "ib"^1 op("id")^1 \ + x_1 y_1 "_"_1 x^1 l^1 "`"^1 attach(I,tl:1,bl:1,tr:1,br:1) + scripts(sum)_1^1 integral_1^1 abs(1/2)_1^1 \ + x^1_1, "("b y")"^1_1 != (b y)^1_1, "[∫]"_1 [integral]_1 $ + +--- math-attach-limit --- +// Test limit. +$ lim_(n->oo \ n "grows") sum_(k=0 \ k in NN)^n k $ + +--- math-attach-force-scripts-and-limits --- +// Test forcing scripts and limits. +$ limits(A)_1^2 != A_1^2 $ +$ scripts(sum)_1^2 != sum_1^2 $ +$ limits(integral)_a^b != integral_a^b $ + +--- issue-math-attach-realize-panic --- +// Error: 25-29 unknown variable: oops +$ attach(A, t: #context oops) $ + +--- math-attach-show-limit --- +// Show and let rules for limits and scripts +#let eq = $ ∫_a^b iota_a^b $ +#eq +#show "∫": math.limits +#show math.iota: math.limits.with(inline: false) +#eq +$iota_a^b$ + +--- math-attach-default-placement --- +// Test default of limit attachments on relations at all sizes +#set page(width: auto) +$ a =^"def" b quad a lt.eq_"really" b quad a arrow.r.long.squiggly^"slowly" b $ +$a =^"def" b quad a lt.eq_"really" b quad a arrow.r.long.squiggly^"slowly" b$ + +$a scripts(=)^"def" b quad a scripts(lt.eq)_"really" b quad a scripts(arrow.r.long.squiggly)^"slowly" b$ + +--- math-attach-integral --- +// Test default of scripts attachments on integrals at display size +$ integral.sect_a^b quad \u{2a1b}_a^b quad limits(\u{2a1b})_a^b $ +$integral.sect_a^b quad \u{2a1b}_a^b quad limits(\u{2a1b})_a^b$ + +--- math-attach-large-operator --- +// Test default of limit attachments on large operators at display size only +$ tack.t.big_0^1 quad \u{02A0A}_0^1 quad join_0^1 $ +$tack.t.big_0^1 quad \u{02A0A}_0^1 quad join_0^1$ diff --git a/tests/suite/math/cancel.typ b/tests/suite/math/cancel.typ new file mode 100644 index 00000000..e2fd5efd --- /dev/null +++ b/tests/suite/math/cancel.typ @@ -0,0 +1,38 @@ +// Tests the cancel() function. + +--- math-cancel-inline --- +// Inline +$a + 5 + cancel(x) + b - cancel(x)$ + +$c + (a dot.c cancel(b dot.c c))/(cancel(b dot.c c))$ + +--- math-cancel-display --- +// Display +#set page(width: auto) +$ a + b + cancel(b + c) - cancel(b) - cancel(c) - 5 + cancel(6) - cancel(6) $ +$ e + (a dot.c cancel((b + c + d)))/(cancel(b + c + d)) $ + +--- math-cancel-inverted --- +// Inverted +$a + cancel(x, inverted: #true) - cancel(x, inverted: #true) + 10 + cancel(y) - cancel(y)$ +$ x + cancel("abcdefg", inverted: #true) $ + +--- math-cancel-cross --- +// Cross +$a + cancel(b + c + d, cross: #true, stroke: #red) + e$ +$ a + cancel(b + c + d, cross: #true) + e $ + +--- math-cancel-customized --- +// Resized and styled +#set page(width: 200pt, height: auto) +$a + cancel(x, length: #200%) - cancel(x, length: #50%, stroke: #(red + 1.1pt))$ +$ b + cancel(x, length: #150%) - cancel(a + b + c, length: #50%, stroke: #(blue + 1.2pt)) $ + +--- math-cancel-angle-absolute --- +// Specifying cancel line angle with an absolute angle +$cancel(x, angle: #0deg) + cancel(x, angle: #45deg) + cancel(x, angle: #90deg) + cancel(x, angle: #135deg)$ + +--- math-cancel-angle-func --- +// Specifying cancel line angle with a function +$x + cancel(y, angle: #{angle => angle + 90deg}) - cancel(z, angle: #(angle => angle + 135deg))$ +$ e + cancel((j + e)/(f + e)) - cancel((j + e)/(f + e), angle: #(angle => angle + 30deg)) $ diff --git a/tests/suite/math/cases.typ b/tests/suite/math/cases.typ new file mode 100644 index 00000000..e6c4956d --- /dev/null +++ b/tests/suite/math/cases.typ @@ -0,0 +1,13 @@ +// Test case distinction. + +--- math-cases --- +$ f(x, y) := cases( + 1 quad &"if" (x dot y)/2 <= 0, + 2 &"if" x divides 2, + 3 &"if" x in NN, + 4 &"else", +) $ + +--- math-cases-gap --- +#set math.cases(gap: 1em) +$ x = cases(1, 2) $ diff --git a/tests/suite/math/class.typ b/tests/suite/math/class.typ new file mode 100644 index 00000000..7aad0446 --- /dev/null +++ b/tests/suite/math/class.typ @@ -0,0 +1,47 @@ +// Test math classes. + +--- math-class-chars --- +// Test characters. +$ a class("normal", +) b \ + a class("binary", .) b \ + lr(class("opening", \/) a/b class("closing", \\)) \ + { x class("fence", \;) x > 0} \ + a class("large", \/) b \ + a class("punctuation", :) b \ + a class("relation", ~) b \ + a + class("unary", times) b \ + class("vary", :) a class("vary", :) b $ + +--- math-class-content --- +// Test custom content. +#let dotsq = square( + size: 0.7em, + stroke: 0.5pt, + align(center+horizon, circle(radius: 0.15em, fill: black)) +) + +$ a dotsq b \ + a class("normal", dotsq) b \ + a class("vary", dotsq) b \ + a + class("vary", dotsq) b \ + a class("punctuation", dotsq) b $ + +--- math-class-nested --- +// Test nested. +#let normal = math.class.with("normal") +#let pluseq = $class("binary", normal(+) normal(=))$ +$ a pluseq 5 $ + +--- math-class-exceptions --- +// Test exceptions. +$ sqrt(3)\/2 quad d_0.d_1d_2 dots $ + +--- math-class-limits --- +// Test if the math class changes the limit configuration. +$ class("normal", ->)_a $ +$class("relation", x)_a$ +$ class("large", x)_a $ +$class("large", ->)_a$ + +$limits(class("normal", ->))_a$ +$ scripts(class("relation", x))_a $ diff --git a/tests/suite/math/delimited.typ b/tests/suite/math/delimited.typ new file mode 100644 index 00000000..98579947 --- /dev/null +++ b/tests/suite/math/delimited.typ @@ -0,0 +1,64 @@ +// Test delimiter matching and scaling. + +--- math-lr-matching --- +// Test automatic matching. +#set page(width:122pt) +$ (a) + {b/2} + abs(a)/2 + (b) $ +$f(x/2) < zeta(c^2 + abs(a + b/2))$ + +--- math-lr-unmatched --- +// Test unmatched. +$[1,2[ = [1,2) != zeta\(x/2\) $ + +--- math-lr-call --- +// Test manual matching. +$ [|a/b|] != lr(|]a/b|]) != [a/b) $ +$ lr(| ]1,2\[ + 1/2|) $ + +--- math-lr-fences --- +// Test fence confusion. +$ |x + |y| + z/a| \ + lr(|x + |y| + z/a|) $ + +--- math-lr-symbol-unmatched --- +// Test that symbols aren't matched automatically. +$ bracket.l a/b bracket.r + = lr(bracket.l a/b bracket.r) $ + +--- math-lr-half --- +// Test half LRs. +$ lr(a/b\]) = a = lr(\{a/b) $ + +--- math-lr-size --- +// Test manual scaling. +$ lr(]sum_(x=1)^n x], size: #70%) + < lr((1, 2), size: #200%) $ + +--- math-lr-shorthands --- +// Test predefined delimiter pairings. +$floor(x/2), ceil(x/2), abs(x), norm(x)$ + +--- math-lr-color --- +// Test colored delimiters +$ lr( + text("(", fill: #green) a/b + text(")", fill: #blue) + ) $ + +--- math-lr-mid --- +// Test middle functions +$ { x mid(|) sum_(i=1)^oo phi_i (x) < 1 } \ + { integral |x| dif x + mid(bar.v.double) + floor(hat(A) mid(|) { x mid(|) y } mid(|) A) } $ + +--- math-lr-unbalanced --- +// Test unbalanced delimiters. +$ 1/(2 (x) $ +$ 1_(2 y (x) () $ +$ 1/(2 y (x) (2(3)) $ + +--- math-lr-weak-spacing --- +// Test ignoring weak spacing immediately after the opening +// and immediately before the closing. +$ [#h(1em, weak: true)A(dif x, f(x) dif x)sum#h(1em, weak: true)] $ diff --git a/tests/suite/math/equation.typ b/tests/suite/math/equation.typ new file mode 100644 index 00000000..dd2745d1 --- /dev/null +++ b/tests/suite/math/equation.typ @@ -0,0 +1,212 @@ +// Test alignment of block equations. +// Test show rules on equations. + +--- math-equation-numbering --- +#set page(width: 150pt) +#set math.equation(numbering: "(I)") + +We define $x$ in preparation of @fib: +$ phi.alt := (1 + sqrt(5)) / 2 $ <ratio> + +With @ratio, we get +$ F_n = round(1 / sqrt(5) phi.alt^n) $ <fib> + +--- math-equation-font --- +// Test different font. +#show math.equation: set text(font: "Fira Math") +$ v := vec(1 + 2, 2 - 4, sqrt(3), arrow(x)) + 1 $ + +--- math-equation-show-rule --- +This is small: $sum_(i=0)^n$ + +#show math.equation: math.display +This is big: $sum_(i=0)^n$ + +--- math-equation-align-unnumbered --- +// Test unnumbered +#let eq(alignment) = { + show math.equation: set align(alignment) + $ a + b = c $ +} + +#eq(center) +#eq(left) +#eq(right) + +#set text(dir: rtl) +#eq(start) +#eq(end) + +--- math-equation-align-numbered --- +// Test numbered +#let eq(alignment) = { + show math.equation: set align(alignment) + $ a + b = c $ +} + +#set math.equation(numbering: "(1)") + +#eq(center) +#eq(left) +#eq(right) + +#set text(dir: rtl) +#eq(start) +#eq(end) + +--- math-equation-number-align --- +#set math.equation(numbering: "(1)") + +$ a + b = c $ + +#show math.equation: set align(center) +$ a + b = c $ +#show math.equation: set align(left) +$ a + b = c $ +#show math.equation: set align(right) +$ a + b = c $ + +#set text(dir: rtl) +#show math.equation: set align(start) +$ a + b = c $ +#show math.equation: set align(end) +$ a + b = c $ + +--- math-equation-number-align-start --- +#set math.equation(numbering: "(1)", number-align: start) + +$ a + b = c $ + +#show math.equation: set align(center) +$ a + b = c $ +#show math.equation: set align(left) +$ a + b = c $ +#show math.equation: set align(right) +$ a + b = c $ + +#set text(dir: rtl) +#show math.equation: set align(start) +$ a + b = c $ +#show math.equation: set align(end) +$ a + b = c $ + +--- math-equation-number-align-end --- +#set math.equation(numbering: "(1)", number-align: end) + +$ a + b = c $ + +#show math.equation: set align(center) +$ a + b = c $ +#show math.equation: set align(left) +$ a + b = c $ +#show math.equation: set align(right) +$ a + b = c $ + +#set text(dir: rtl) +#show math.equation: set align(start) +$ a + b = c $ +#show math.equation: set align(end) +$ a + b = c $ + +--- math-equation-number-align-left --- +#set math.equation(numbering: "(1)", number-align: left) + +$ a + b = c $ + +#show math.equation: set align(center) +$ a + b = c $ +#show math.equation: set align(left) +$ a + b = c $ +#show math.equation: set align(right) +$ a + b = c $ + +#set text(dir: rtl) +#show math.equation: set align(start) +$ a + b = c $ +#show math.equation: set align(end) +$ a + b = c $ + +--- math-equation-number-align-right --- +#set math.equation(numbering: "(1)", number-align: right) + +$ a + b = c $ + +#show math.equation: set align(center) +$ a + b = c $ +#show math.equation: set align(left) +$ a + b = c $ +#show math.equation: set align(right) +$ a + b = c $ + +#set text(dir: rtl) +#show math.equation: set align(start) +$ a + b = c $ +#show math.equation: set align(end) +$ a + b = c $ + +--- math-equation-number-align-center --- +// Error: 52-58 expected `start`, `left`, `right`, or `end`, found center +#set math.equation(numbering: "(1)", number-align: center) + +--- math-equation-number-align-center-bottom --- +// Error: 52-67 expected `start`, `left`, `right`, or `end`, found center +#set math.equation(numbering: "(1)", number-align: center + bottom) + +--- math-equation-number-align-multiline --- +#set math.equation(numbering: "(1)") + +$ p &= ln a b \ + &= ln a + ln b $ + +--- math-equation-number-align-multiline-top-start --- +#set math.equation(numbering: "(1)", number-align: top+start) + +$ p &= ln a b \ + &= ln a + ln b $ + +--- math-equation-number-align-multiline-bottom --- +#show math.equation: set align(left) +#set math.equation(numbering: "(1)", number-align: bottom) + +$ q &= ln sqrt(a b) \ + &= 1/2 (ln a + ln b) $ + +--- math-equation-number-align-multiline-expand --- +// Tests that if the numbering's layout box vertically exceeds the box of +// the equation frame's boundary, the latter's frame is resized correctly +// to encompass the numbering. #box() below delineates the resized frame. +// +// A row with "-" only has a height that's smaller than the height of the +// numbering's layout box. Note we use pattern "1" here, not "(1)", since +// the parenthesis exceeds the numbering's layout box, due to the default +// settings of top-edge and bottom-edge of the TextElem that laid it out. +#set math.equation(numbering: "1", number-align: top) +#box( +$ - &- - \ + a &= b $, +fill: silver) + +#set math.equation(numbering: "1", number-align: horizon) +#box( +$ - - - $, +fill: silver) + +#set math.equation(numbering: "1", number-align: bottom) +#box( +$ a &= b \ + - &- - $, +fill: silver) + +--- issue-numbering-hint --- +// In this bug, the hint and error messages for an equation +// being reference mentioned that it was a "heading" and was +// lacking the proper path. +#set page(height: 70pt) + +$ + Delta = b^2 - 4 a c +$ <quadratic> + +// Error: 14-24 cannot reference equation without numbering +// Hint: 14-24 you can enable equation numbering with `#set math.equation(numbering: "1.")` +Looks at the @quadratic formula. diff --git a/tests/suite/math/frac.typ b/tests/suite/math/frac.typ new file mode 100644 index 00000000..b3ca8aa0 --- /dev/null +++ b/tests/suite/math/frac.typ @@ -0,0 +1,43 @@ +// Test fractions. + +--- math-frac-baseline --- +// Test that denominator baseline matches in the common case. +$ x = 1/2 = a/(a h) = a/a = a/(1/2) $ + +--- math-frac-paren-removal --- +// Test parenthesis removal. +$ (|x| + |y|)/2 < [1+2]/3 $ + +--- math-frac-large --- +// Test large fraction. +$ x = (-b plus.minus sqrt(b^2 - 4a c))/(2a) $ + +--- math-binom --- +// Test binomial. +$ binom(circle, square) $ + +--- math-binom-multiple --- +// Test multinomial coefficients. +$ binom(n, k_1, k_2, k_3) $ + +--- math-binom-missing-lower --- +// Error: 3-13 missing argument: lower +$ binom(x^2) $ + +--- math-dif --- +// Test dif. +$ (dif y)/(dif x), dif/x, x/dif, dif/dif \ + frac(dif y, dif x), frac(dif, x), frac(x, dif), frac(dif, dif) $ + +--- math-frac-associativity --- +// Test associativity. +$ 1/2/3 = (1/2)/3 = 1/(2/3) $ + +--- math-frac-precedence --- +// Test precedence. +$ a_1/b_2, 1/f(x), zeta(x)/2, "foo"[|x|]/2 \ + 1.2/3.7, 2.3^3.4 \ + 🏳️🌈[x]/2, f [x]/2, phi [x]/2, 🏳️🌈 [x]/2 \ + +[x]/2, 1(x)/2, 2[x]/2 \ + (a)b/2, b(a)[b]/2 \ + n!/2, 5!/2, n !/2, 1/n!, 1/5! $ diff --git a/tests/suite/math/interactions.typ b/tests/suite/math/interactions.typ new file mode 100644 index 00000000..37185962 --- /dev/null +++ b/tests/suite/math/interactions.typ @@ -0,0 +1,95 @@ +// Test interactions with styling and normal layout. +// Hint: They are bad ... + +--- math-nested-normal-layout --- +// Test images and font fallback. +#let monkey = move(dy: 0.2em, image("/assets/images/monkey.svg", height: 1em)) +$ sum_(i=#emoji.apple)^#emoji.apple.red i + monkey/2 $ + +--- math-table --- +// Test tables. +$ x := #table(columns: 2)[x][y]/mat(1, 2, 3) + = #table[A][B][C] $ + +--- math-equation-auto-wrapping --- +// Test non-equation math directly in content. +#math.attach($a$, t: [b]) + +--- math-font-switch --- +// Test font switch. +#let here = text.with(font: "Noto Sans") +$#here[f] := #here[Hi there]$. + +--- math-box-without-baseline --- +// Test boxes without a baseline act as if the baseline is at the base +#{ + box(stroke: 0.2pt, $a #box(stroke: 0.2pt, $a$)$) + h(12pt) + box(stroke: 0.2pt, $a #box(stroke: 0.2pt, $g$)$) + h(12pt) + box(stroke: 0.2pt, $g #box(stroke: 0.2pt, $g$)$) +} + +--- math-box-with-baseline --- +// Test boxes with a baseline are respected +#box(stroke: 0.2pt, $a #box(baseline:0.5em, stroke: 0.2pt, $a$)$) + +--- issue-2821-missing-fields --- +// Issue #2821: Setting a figure's supplement to none removes the field +#show figure.caption: it => { + assert(it.has("supplement")) + assert(it.supplement == none) +} +#figure([], caption: [], supplement: none) + +--- math-symbol-show-rule --- +// Test using rules for symbols +#show sym.tack: it => $#h(1em) it #h(1em)$ +$ a tack b $ + +--- issue-math-realize-show --- +// Test that content in math can be realized without breaking +// nested equations. +#let my = $pi$ +#let f1 = box(baseline: 10pt, [f]) +#let f2 = context f1 +#show math.vec: [nope] + +$ pi a $ +$ my a $ +$ 1 + sqrt(x/2) + sqrt(#hide($x/2$)) $ +$ a x #link("url", $+ b$) $ +$ f f1 f2 $ +$ vec(1,2) * 2 $ + +--- issue-math-realize-hide --- +$ x^2 #hide[$(>= phi.alt) union y^2 0$] z^2 $ +Hello #hide[there $x$] +and #hide[$ f(x) := x^2 $] + +--- issue-math-realize-scripting --- +// Test equations can embed equation pieces built by functions +#let foo(v1, v2) = { + // Return an equation piece that would've been rendered in + // inline style if the piece is not embedded + $v1 v2^2$ +} +#let bar(v1, v2) = { + // Return an equation piece that would've been rendered in + // block style if the piece is not embedded + $ v1 v2^2 $ +} +#let baz(..sink) = { + // Return an equation piece built by joining arrays + sink.pos().map(x => $hat(#x)$).join(sym.and) +} + +Inline $2 foo(alpha, (M+foo(a, b)))$. + +Inline $2 bar(alpha, (M+foo(a, b)))$. + +Inline $2 baz(x,y,baz(u, v))$. + +$ 2 foo(alpha, (M+foo(a, b))) $ +$ 2 bar(alpha, (M+foo(a, b))) $ +$ 2 baz(x,y,baz(u, v)) $ diff --git a/tests/suite/math/mat.typ b/tests/suite/math/mat.typ new file mode 100644 index 00000000..e6148a34 --- /dev/null +++ b/tests/suite/math/mat.typ @@ -0,0 +1,163 @@ +// Test matrices. + +--- math-mat-semicolon --- +// Test semicolon syntax. +#set align(center) +$mat() dot + mat(;) dot + mat(1, 2) dot + mat(1, 2;) \ + mat(1; 2) dot + mat(1, 2; 3, 4) dot + mat(1 + &2, 1/2; &3, 4)$ + +--- math-mat-sparse --- +// Test sparse matrix. +$ mat( + 1, 2, ..., 10; + 2, 2, ..., 10; + dots.v, dots.v, dots.down, dots.v; + 10, 10, ..., 10; +) $ + +--- math-mat-baseline --- +// Test baseline alignment. +$ mat( + a, b^2; + sum_(x \ y) x, a^(1/2); + zeta, alpha; +) $ + +--- math-mat-delim-set --- +// Test alternative delimiter with set rule. +#set math.mat(delim: "[") +$ mat(1, 2; 3, 4) $ +$ a + mat(delim: #none, 1, 2; 3, 4) + b $ + +--- math-mat-delim-direct --- +// Test alternative math delimiter directly in call. +#set align(center) +#grid( + columns: 3, + gutter: 10pt, + + $ mat(1, 2, delim: "[") $, + $ mat(1, 2; delim: "[") $, + $ mat(delim: "[", 1, 2) $, + + $ mat(1; 2; delim: "[") $, + $ mat(1; delim: "[", 2) $, + $ mat(delim: "[", 1; 2) $, + + $ mat(1, 2; delim: "[", 3, 4) $, + $ mat(delim: "[", 1, 2; 3, 4) $, + $ mat(1, 2; 3, 4; delim: "[") $, +) + +--- math-mat-gap --- +#set math.mat(gap: 1em) +$ mat(1, 2; 3, 4) $ + +--- math-mat-gaps --- +#set math.mat(row-gap: 1em, column-gap: 2em) +$ mat(1, 2; 3, 4) $ + +--- math-mat-augment --- +// Test matrix line drawing (augmentation). +#grid( + columns: 2, + gutter: 10pt, + + $ mat(10, 2, 3, 4; 5, 6, 7, 8; augment: #3) $, + $ mat(10, 2, 3, 4; 5, 6, 7, 8; augment: #(-1)) $, + $ mat(100, 2, 3; 4, 5, 6; 7, 8, 9; augment: #(hline: 2)) $, + $ mat(100, 2, 3; 4, 5, 6; 7, 8, 9; augment: #(hline: -1)) $, + $ mat(100, 2, 3; 4, 5, 6; 7, 8, 9; augment: #(hline: 1, vline: 1)) $, + $ mat(100, 2, 3; 4, 5, 6; 7, 8, 9; augment: #(hline: -2, vline: -2)) $, + $ mat(100, 2, 3; 4, 5, 6; 7, 8, 9; augment: #(vline: 2, stroke: 1pt + blue)) $, + $ mat(100, 2, 3; 4, 5, 6; 7, 8, 9; augment: #(vline: -1, stroke: 1pt + blue)) $, +) + +--- math-mat-augment-set --- +// Test using matrix line drawing with a set rule. +#set math.mat(augment: (hline: 2, vline: 1, stroke: 2pt + green)) +$ mat(1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 1) $ + +#set math.mat(augment: 2) +$ mat(1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 1) $ + +#set math.mat(augment: none) + +--- math-mat-augment-line-out-of-bounds --- +// Error: 3-37 cannot draw a vertical line after column 3 of a matrix with 3 columns +$ mat(1, 0, 0; 0, 1, 1; augment: #3) $, + +--- math-mat-align-explicit--alternating --- +// Test alternating explicit alignment in a matrix. +$ mat( + "a" & "a a a" & "a a"; + "a a" & "a a" & "a"; + "a a a" & "a" & "a a a"; +) $ + +--- math-mat-align-implicit --- +// Test alignment in a matrix. +$ mat( + "a", "a a a", "a a"; + "a a", "a a", "a"; + "a a a", "a", "a a a"; +) $ + +--- math-mat-align-explicit-left --- +// Test explicit left alignment in a matrix. +$ mat( + &"a", &"a a a", &"a a"; + &"a a", &"a a", &"a"; + &"a a a", &"a", &"a a a"; +) $ + +--- math-mat-align-explicit-right --- +// Test explicit right alignment in a matrix. +$ mat( + "a"&, "a a a"&, "a a"&; + "a a"&, "a a"&, "a"&; + "a a a"&, "a"&, "a a a"&; +) $ + +--- math-mat-align-complex --- +// Test #460 equations. +#let stop = { + math.class("punctuation",$.$) +} +$ mat(&a+b,c;&d, e) $ +$ mat(&a+b&,c;&d&, e) $ +$ mat(&&&a+b,c;&&&d, e) $ +$ mat(stop &a+b&stop,c;...stop stop&d&...stop stop, e) $ + +--- math-mat-align-signed-numbers --- +// Test #454 equations. +$ mat(-1, 1, 1; 1, -1, 1; 1, 1, -1) $ +$ mat(-1&, 1&, 1&; 1&, -1&, 1&; 1&, 1&, -1&) $ +$ mat(-1&, 1&, 1&; 1, -1, 1; 1, 1, -1) $ +$ mat(&-1, &1, &1; 1, -1, 1; 1, 1, -1) $ + +--- math-mat-bad-comma --- +// This error message is bad. +// Error: 13-14 expected array, found content +$ mat(1, 2; 3, 4, delim: "[") $, + +--- issue-852-mat-type --- +$ mat(B, A B) $ +$ mat(B, A B, dots) $ +$ mat(B, A B, dots;) $ +$ mat(#1, #(foo: "bar")) $ + +--- issue-2268-mat-augment-color --- +// The augment line should be of the same color as the text +#set text( + font: "New Computer Modern", + lang: "en", + fill: yellow, +) + +$mat(augment: #1, M, v) arrow.r.squiggly mat(augment: #1, R, b)$ diff --git a/tests/suite/math/multiline.typ b/tests/suite/math/multiline.typ new file mode 100644 index 00000000..85433627 --- /dev/null +++ b/tests/suite/math/multiline.typ @@ -0,0 +1,109 @@ +// Test multiline math. + +--- math-align-basic --- +// Test basic alignment. +$ x &= x + y \ + &= x + 2z \ + &= sum x dot 2z $ + +--- math-align-wider-first-column --- +// Test text before first alignment point. +$ x + 1 &= a^2 + b^2 \ + y &= a + b^2 \ + z &= alpha dot beta $ + +--- math-align-aligned-in-source --- +// Test space between inner alignment points. +$ a + b &= 2 + 3 &= 5 \ + b &= c &= 3 $ + +--- math-align-cases --- +// Test in case distinction. +$ f := cases( + 1 + 2 &"iff" &x, + 3 &"if" &y, +) $ + +--- math-align-lines-mixed --- +// Test mixing lines with and some without alignment points. +$ "abc" &= c \ + &= d + 1 \ + = x $ + +--- math-attach-subscript-multiline --- +// Test multiline subscript. +$ sum_(n in NN \ n <= 5) n = (5(5+1))/2 = 15 $ + +--- math-multiline-no-trailing-linebreak --- +// Test no trailing line break. +$ +"abc" &= c +$ +No trailing line break. + +--- math-multiline-trailing-linebreak --- +// Test single trailing line break. +$ +"abc" &= c \ +$ +One trailing line break. + +--- math-multiline-multiple-trailing-linebreaks --- +// Test multiple trailing line breaks. +$ +"abc" &= c \ \ \ +$ +Multiple trailing line breaks. + +--- math-linebreaking-after-binop-and-rel --- +// Basic breaking after binop, rel +#let hrule(x) = box(line(length: x)) +#hrule(45pt)$e^(pi i)+1 = 0$\ +#hrule(55pt)$e^(pi i)+1 = 0$\ +#hrule(70pt)$e^(pi i)+1 = 0$ + +--- math-linebreaking-lr --- +// LR groups prevent linbreaking. +#let hrule(x) = box(line(length: x)) +#hrule(76pt)$a+b$\ +#hrule(74pt)$(a+b)$\ +#hrule(74pt)$paren.l a+b paren.r$ + +--- math-linebreaking-multiline --- +// Multiline yet inline does not linebreak +#let hrule(x) = box(line(length: x)) +#hrule(80pt)$a + b \ c + d$\ + +--- math-linebreaking-trailing-linebreak --- +// A single linebreak at the end still counts as one line. +#let hrule(x) = box(line(length: x)) +#hrule(60pt)$e^(pi i)+1 = 0\ $ + +--- math-linebreaking-in-box --- +// Inline, in a box, doesn't linebreak. +#let hrule(x) = box(line(length: x)) +#hrule(80pt)#box($a+b$) + +--- math-linebreaking-between-consecutive-relations --- +// A relation followed by a relation doesn't linebreak +#let hrule(x) = box(line(length: x)) +#hrule(70pt)$a < = b$\ +#hrule(74pt)$a < = b$ + +--- math-linebreaking-after-relation-without-space --- +// Line breaks can happen after a relation even if there is no +// explicit space. +#let hrule(x) = box(line(length: x)) +#hrule(90pt)$<;$\ +#hrule(95pt)$<;$\ +#hrule(90pt)$<)$\ +#hrule(95pt)$<)$ + +--- math-linebreaking-empty --- +// Verify empty rows are handled ok. +$ $\ +Nothing: $ $, just empty. + +--- issue-1948-math-text-break --- +// Test text with linebreaks in math. +$ x := "a\nb\nc\nd\ne" $ diff --git a/tests/suite/math/op.typ b/tests/suite/math/op.typ new file mode 100644 index 00000000..4139a08b --- /dev/null +++ b/tests/suite/math/op.typ @@ -0,0 +1,30 @@ +// Test text operators. + +--- math-op-predefined --- +// Test predefined. +$ max_(1<=n<=m) n $ + +--- math-op-call --- +// With or without parens. +$ &sin x + log_2 x \ + = &sin(x) + log_2(x) $ + +--- math-op-scripts-vs-limits --- +// Test scripts vs limits. +#set page(width: auto) +#set text(font: "New Computer Modern") +Discuss $lim_(n->oo) 1/n$ now. +$ lim_(n->infinity) 1/n = 0 $ + +--- math-op-custom --- +// Test custom operator. +$ op("myop", limits: #false)_(x:=1) x \ + op("myop", limits: #true)_(x:=1) x $ + +--- math-op-styled --- +// Test styled operator. +$ bold(op("bold", limits: #true))_x y $ + +--- math-non-math-content --- +// With non-text content +$ op(#underline[ul]) a $ diff --git a/tests/suite/math/primes.typ b/tests/suite/math/primes.typ new file mode 100644 index 00000000..e10f8876 --- /dev/null +++ b/tests/suite/math/primes.typ @@ -0,0 +1,50 @@ +--- math-primes --- +// Test dedicated syntax for primes +$a'$, $a'''_b$, $'$, $'''''''$ + +--- math-primes-spaces --- +// Test spaces between +$a' ' '$, $' ' '$, $a' '/b$ + +--- math-primes-complex --- +// Test complex prime combinations +$a'_b^c$, $a_b'^c$, $a_b^c'$, $a_b'^c'^d'$ + +$(a'_b')^(c'_d')$, $a'/b'$, $a_b'/c_d'$ + +$∫'$, $∑'$, $ ∑'_S' $ + +--- math-primes-attach --- +// Test attaching primes only +$a' = a^', a_', a_'''^''^'$ + +--- math-primes-scripts --- +// Test primes always attaching as scripts +$ x' $ +$ x^' $ +$ attach(x, t: ') $ +$ <' $ +$ attach(<, br: ') $ +$ op(<, limits: #true)' $ +$ limits(<)' $ + +--- math-primes-limits --- +// Test forcefully attaching primes as limits +$ attach(<, t: ') $ +$ <^' $ +$ attach(<, b: ') $ +$ <_' $ + +$ limits(x)^' $ +$ attach(limits(x), t: ') $ + +--- math-primes-after-code-expr --- +// Test prime symbols after code mode. +#let g = $f$ +#let gg = $f$ + +$ + #(g)' #g' #g ' \ + #g''''''''''''''''' \ + gg' +$ diff --git a/tests/suite/math/root.typ b/tests/suite/math/root.typ new file mode 100644 index 00000000..a690802e --- /dev/null +++ b/tests/suite/math/root.typ @@ -0,0 +1,45 @@ +// Test roots. + +--- math-root-basic --- +// Test root with more than one character. +$A = sqrt(x + y) = c$ + +--- math-root-radical-attachment --- +// Test root size with radicals containing attachments. +$ sqrt(a) quad + sqrt(f) quad + sqrt(q) quad + sqrt(a^2) \ + sqrt(n_0) quad + sqrt(b^()) quad + sqrt(b^2) quad + sqrt(q_1^2) $ + +--- math-root-precomposed --- +// Test precomposed vs constructed roots. +// 3 and 4 are precomposed. +$sqrt(x)$ +$root(2, x)$ +$root(3, x)$ +$root(4, x)$ +$root(5, x)$ + +--- math-root-large-body --- +// Test large bodies +$ sqrt([|x|]^2 + [|y|]^2) < [|z|] $ +$ v = sqrt((1/2) / (4/5)) + = root(3, (1/2/3) / (4/5/6)) + = root(4, ((1/2) / (3/4)) / ((1/2) / (3/4))) $ + +--- math-root-large-index --- +// Test large index. +$ root(2, x) quad + root(3/(2/1), x) quad + root(1/11, x) quad + root(1/2/3, 1) $ + +--- math-root-syntax --- +// Test shorthand. +$ √2^3 = sqrt(2^3) $ +$ √(x+y) quad ∛x quad ∜x $ +$ (√2+3) = (sqrt(2)+3) $ diff --git a/tests/suite/math/size.typ b/tests/suite/math/size.typ new file mode 100644 index 00000000..d0d41dc9 --- /dev/null +++ b/tests/suite/math/size.typ @@ -0,0 +1,9 @@ +--- math-size --- +// Test forcing math size +$a/b, display(a/b), display(a)/display(b), inline(a/b), script(a/b), sscript(a/b) \ + mono(script(a/b)), script(mono(a/b))\ + script(a^b, cramped: #true), script(a^b, cramped: #false)$ + +--- issue-3658-math-size --- +$ #rect[$1/2$] $ +$#rect[$1/2$]$ diff --git a/tests/suite/math/spacing.typ b/tests/suite/math/spacing.typ new file mode 100644 index 00000000..2a387f92 --- /dev/null +++ b/tests/suite/math/spacing.typ @@ -0,0 +1,59 @@ +// Test spacing in math formulas. + +--- math-spacing-basic --- +// Test spacing cases. +$ä, +, c, (, )$ \ +$=), (+), {times}$ \ +$⟧<⟦, abs(-), [=$ \ +$a=b, a==b$ \ +$-a, +a$ \ +$a not b$ \ +$a+b, a*b$ \ +$sum x, sum(x)$ \ +$sum product x$ \ +$f(x), zeta(x), "frac"(x)$ \ +$a+dots.c+b$ +$f(x) sin(y)$ + +--- math-spacing-kept-spaces --- +// Test ignored vs non-ignored spaces. +$f (x), f(x)$ \ +$[a|b], [a | b]$ \ +$a"is"b, a "is" b$ + +--- math-spacing-predefined --- +// Test predefined spacings. +$a thin b, a med b, a thick b, a quad b$ \ +$a = thin b$ \ +$a - b equiv c quad (mod 2)$ + +--- math-spacing-set-comprehension --- +// Test spacing for set comprehension. +#set page(width: auto) +$ { x in RR | x "is natural" and x < 10 } $ + +--- math-spacing-decorated --- +// Test spacing for operators with decorations and modifiers on them +#set page(width: auto) +$a equiv b + c - d => e log 5 op("ln") 6$ \ +$a cancel(equiv) b overline(+) c arrow(-) d hat(=>) e cancel(log) 5 dot(op("ln")) 6$ \ +$a overbrace(equiv) b underline(+) c grave(-) d underbracket(=>) e circle(log) 5 caron(op("ln")) 6$ \ +\ +$a attach(equiv, tl: a, tr: b) b attach(limits(+), t: a, b: b) c tilde(-) d breve(=>) e attach(limits(log), t: a, b: b) 5 attach(op("ln"), tr: a, bl: b) 6$ + +--- math-spacing-weak --- +// Test weak spacing +$integral f(x) dif x$, +// Not weak +$integral f(x) thin dif x$, +// Both are weak, collide +$integral f(x) #h(0.166em, weak: true)dif x$ + +--- issue-1052-math-number-spacing --- +// Test spacing after numbers in math. +$ +10degree \ +10 degree \ +10.1degree \ +10.1 degree +$ diff --git a/tests/suite/math/style.typ b/tests/suite/math/style.typ new file mode 100644 index 00000000..09ddd3c1 --- /dev/null +++ b/tests/suite/math/style.typ @@ -0,0 +1,34 @@ +// Test text styling in math. + +--- math-style-italic-default --- +// Test italic defaults. +$a, A, delta, ϵ, diff, Delta, ϴ$ + +--- math-style --- +// Test forcing a specific style. +$A, italic(A), upright(A), bold(A), bold(upright(A)), \ + serif(A), sans(A), cal(A), frak(A), mono(A), bb(A), \ + italic(diff), upright(diff), \ + bb("hello") + bold(cal("world")), \ + mono("SQRT")(x) wreath mono(123 + 456)$ + +--- math-style-exceptions --- +// Test a few style exceptions. +$h, bb(N), cal(R), Theta, italic(Theta), sans(Theta), sans(italic(Theta)) \ + bb(d), bb(italic(d)), italic(bb(d)), bb(e), bb(italic(e)), italic(bb(e)) \ + bb(i), bb(italic(i)), italic(bb(i)), bb(j), bb(italic(j)), italic(bb(j)) \ + bb(D), bb(italic(D)), italic(bb(D))$ + +--- math-style-greek-exceptions --- +// Test a few greek exceptions. +$bb(Gamma) , bb(gamma), bb(Pi), bb(pi), bb(sum)$ + +--- math-style-hebrew-exceptions --- +// Test hebrew exceptions. +$aleph, beth, gimel, daleth$ + +--- issue-3650-italic-equation --- +_abc $sin(x) "abc"$_ \ +$italic(sin(x) "abc" #box[abc])$ \ +*abc $sin(x) "abc"$* \ +$bold(sin(x) "abc" #box[abc])$ \ diff --git a/tests/suite/math/syntax.typ b/tests/suite/math/syntax.typ new file mode 100644 index 00000000..fcb8b89e --- /dev/null +++ b/tests/suite/math/syntax.typ @@ -0,0 +1,34 @@ +// Test math syntax. + +--- math-call-non-func --- +$ pi(a) $ +$ pi(a,) $ +$ pi(a,b) $ +$ pi(a,b,) $ + +--- math-unicode --- +// Test Unicode math. +$ ∑_(i=0)^ℕ a ∘ b = \u{2211}_(i=0)^NN a compose b $ + +--- math-shorthandes --- +// Test a few shorthands. +$ underline(f' : NN -> RR) \ + n |-> cases( + [|1|] &"if" n >>> 10, + 2 * 3 &"if" n != 5, + 1 - 0 thick &..., + ) $ + +--- math-common-symbols --- +// Test common symbols. +$ dot \ dots \ ast \ tilde \ star $ + +--- issue-2044-invalid-parsed-ident --- +// In this bug, the dot at the end was causing the right parenthesis to be +// parsed as an identifier instead of the closing right parenthesis. +$floor(phi.alt.)$ +$floor(phi.alt. )$ + +--- math-unclosed --- +// Error: 1-2 unclosed delimiter +$a diff --git a/tests/suite/math/text.typ b/tests/suite/math/text.typ new file mode 100644 index 00000000..760910f4 --- /dev/null +++ b/tests/suite/math/text.typ @@ -0,0 +1,45 @@ +// Test that setting font features in math.equation has an effect. + +--- math-font-fallback --- +// Test font fallback. +$ よ and 🏳️🌈 $ + +--- math-text-color --- +// Test text properties. +$text(#red, "time"^2) + sqrt("place")$ + +--- math-font-features --- +$ nothing $ +$ "hi ∅ hey" $ +$ sum_(i in NN) 1 + i $ +#show math.equation: set text(features: ("cv01",), fallback: false) +$ nothing $ +$ "hi ∅ hey" $ +$ sum_(i in NN) 1 + i $ + +--- math-optical-size-nested-scripts --- +// Test transition from script to scriptscript. +#[ +#set text(size:20pt) +$ e^(e^(e^(e))) $ +] +A large number: $e^(e^(e^(e)))$. + +--- math-optical-size-primes --- +// Test prime/double prime via scriptsize +#let prime = [ \u{2032} ] +#let dprime = [ \u{2033} ] +#let tprime = [ \u{2034} ] +$ y^dprime-2y^prime + y = 0 $ +$y^dprime-2y^prime + y = 0$ +$ y^tprime_3 + g^(prime 2) $ + +--- math-optical-size-prime-large-operator --- +// Test prime superscript on large symbol +$ scripts(sum_(k in NN))^prime 1/k^2 $ +$sum_(k in NN)^prime 1/k^2$ + +--- math-optical-size-frac-script-script --- +// Test script-script in a fraction. +$ 1/(x^A) $ +#[#set text(size:18pt); $1/(x^A)$] vs. #[#set text(size:14pt); $x^A$] diff --git a/tests/suite/math/underover.typ b/tests/suite/math/underover.typ new file mode 100644 index 00000000..0768bf73 --- /dev/null +++ b/tests/suite/math/underover.typ @@ -0,0 +1,21 @@ +// Test under/over things. + +--- math-underover-brace --- +// Test braces. +$ x = underbrace( + 1 + 2 + ... + 5, + underbrace("numbers", x + y) +) $ + +--- math-underover-line-bracket --- +// Test lines and brackets. +$ x = overbracket( + overline(underline(x + y)), + 1 + 2 + ... + 5, +) $ + +--- math-underover-brackets --- +// Test brackets. +$ underbracket([1, 2/3], "relevant stuff") + arrow.l.r.double.long + overbracket([4/5,6], "irrelevant stuff") $ diff --git a/tests/suite/math/vec.typ b/tests/suite/math/vec.typ new file mode 100644 index 00000000..312c0ee4 --- /dev/null +++ b/tests/suite/math/vec.typ @@ -0,0 +1,27 @@ +// Test vectors. + +--- math-vec-gap --- +#set math.vec(gap: 1em) +$ vec(1, 2) $ + + +--- math-vec-align-explicit-alternating --- +// Test alternating alignment in a vector. +$ vec( + "a" & "a a a" & "a a", + "a a" & "a a" & "a", + "a a a" & "a" & "a a a", +) $ + +--- math-vec-wide --- +// Test wide cell. +$ v = vec(1, 2+3, 4) $ + +--- math-vec-delim-set --- +// Test alternative delimiter. +#set math.vec(delim: "[") +$ vec(1, 2) $ + +--- math-vec-delim-invalid --- +// Error: 22-25 expected "(", "[", "{", "|", "||", or none +#set math.vec(delim: "%") diff --git a/tests/suite/model/bibliography.typ b/tests/suite/model/bibliography.typ new file mode 100644 index 00000000..7197082f --- /dev/null +++ b/tests/suite/model/bibliography.typ @@ -0,0 +1,55 @@ +// Test citations and bibliographies. + +--- bibliography-basic --- +#set page(width: 200pt) + += Details +See also @arrgh #cite(<distress>, supplement: [p.~22]), @arrgh[p.~4], and @distress[p.~5]. +#bibliography("/assets/bib/works.bib") + +--- bibliography-before-content --- +// Test unconventional order. +#set page(width: 200pt) +#bibliography( + "/assets/bib/works.bib", + title: [Works to be cited], + style: "chicago-author-date", +) +#line(length: 100%) + +As described by #cite(<netwok>, form: "prose"), +the net-work is a creature of its own. +This is close to piratery! @arrgh +And quark! @quark + +--- bibliography-multiple-files --- +#set page(width: 200pt) +#set heading(numbering: "1.") +#show bibliography: set heading(numbering: "1.") + += Multiple Bibs +Now we have multiple bibliographies containing @glacier-melt @keshav2007read +#bibliography(("/assets/bib/works.bib", "/assets/bib/works_too.bib")) + +--- bibliography-duplicate-key --- +// Error: 15-65 duplicate bibliography keys: netwok, issue201, arrgh, quark, distress, glacier-melt, tolkien54, DBLP:books/lib/Knuth86a, sharing, restful, mcintosh_anxiety, psychology25 +#bibliography(("/assets/bib/works.bib", "/assets/bib/works.bib")) + +--- bibliography-ordering --- +#set page(width: 300pt) + +@mcintosh_anxiety +@psychology25 + +#bibliography("/assets/bib/works.bib") + +--- bibliography-full --- +// LARGE +#set page(paper: "a6", height: 170mm) +#bibliography("/assets/bib/works.bib", full: true) + +--- bibliography-math --- +#set page(width: 200pt) + +@Zee04 +#bibliography("/assets/bib/works_too.bib", style: "mla") diff --git a/tests/suite/model/cite.typ b/tests/suite/model/cite.typ new file mode 100644 index 00000000..c6bdccb1 --- /dev/null +++ b/tests/suite/model/cite.typ @@ -0,0 +1,92 @@ +--- cite-footnote --- +Hello @netwok +And again: @netwok + +#pagebreak() +#bibliography("/assets/bib/works.bib", style: "chicago-notes") + +--- cite-form --- +#set page(width: 200pt) + +Nothing: #cite(<arrgh>, form: none) + +#cite(<netwok>, form: "prose") say stuff. + +#bibliography("/assets/bib/works.bib", style: "apa") + +--- cite-group --- +A#[@netwok@arrgh]B \ +A@netwok@arrgh B \ +A@netwok @arrgh B \ +A@netwok @arrgh. B \ + +A @netwok#[@arrgh]B \ +A @netwok@arrgh, B \ +A @netwok @arrgh, B \ +A @netwok @arrgh. B \ + +A#[@netwok @arrgh @quark]B. \ +A @netwok @arrgh @quark B. \ +A @netwok @arrgh @quark, B. + +#set text(0pt) +#bibliography("/assets/bib/works.bib") + +--- cite-grouping-and-ordering --- +@mcintosh_anxiety +@psychology25 +@netwok +@issue201 +@arrgh +@quark +@distress, +@glacier-melt +@issue201 +@tolkien54 +@sharing +@restful + +#show bibliography: none +#bibliography("/assets/bib/works.bib") + +--- issue-785-cite-locate --- +// Test citation in other introspection. +#set page(width: 180pt) +#set heading(numbering: "1") + +#outline( + title: [List of Figures], + target: figure.where(kind: image), +) + +#pagebreak() + += Introduction <intro> +#figure( + rect[-- PIRATE --], + caption: [A pirate @arrgh in @intro], +) + +#context [Citation @distress on page #here().page()] + +#pagebreak() +#bibliography("/assets/bib/works.bib", style: "chicago-notes") + +--- issue-1597-cite-footnote --- +// Tests that when a citation footnote is pushed to next page, things still +// work as expected. +#set page(height: 60pt) +#lorem(4) + +#footnote[@netwok] +#show bibliography: none +#bibliography("/assets/bib/works.bib") + +--- issue-2531-cite-show-set --- +// Test show set rules on citations. +#show cite: set text(red) +A @netwok @arrgh. +B #cite(<netwok>) #cite(<arrgh>). + +#show bibliography: none +#bibliography("/assets/bib/works.bib") diff --git a/tests/suite/model/document.typ b/tests/suite/model/document.typ new file mode 100644 index 00000000..6f8e7131 --- /dev/null +++ b/tests/suite/model/document.typ @@ -0,0 +1,36 @@ +// Test document and page-level styles. + +--- document-set-title --- +// This is okay. +#set document(title: [Hello]) +What's up? + +--- document-set-author-date --- +// This, too. +#set document(author: ("A", "B"), date: datetime.today()) + +--- document-date-bad --- +// Error: 21-28 expected datetime, none, or auto, found string +#set document(date: "today") + +--- document-author-bad --- +// This, too. +// Error: 23-29 expected string, found integer +#set document(author: (123,)) +What's up? + +--- document-set-after-content --- +Hello + +// Error: 2-30 document set rules must appear before any content +#set document(title: [Hello]) + +--- document-constructor --- +// Error: 2-12 can only be used in set rules +#document() + +--- document-set-in-container --- +#box[ + // Error: 4-32 document set rules are not allowed inside of containers + #set document(title: [Hello]) +] diff --git a/tests/suite/model/emph-strong.typ b/tests/suite/model/emph-strong.typ new file mode 100644 index 00000000..2af8bb16 --- /dev/null +++ b/tests/suite/model/emph-strong.typ @@ -0,0 +1,74 @@ +// Test emph and strong. + +--- emph-syntax --- +// Basic. +_Emphasized and *strong* words!_ + +// Inside of a word it's a normal underscore or star. +hello_world Nutzer*innen + +// CJK characters will not need spaces. +中文一般使用*粗体*或者_楷体_来表示强调。 + +日本語では、*太字*や_斜体_を使って強調します。 + +中文中混有*Strong*和_Empasis_。 + +// Can contain paragraph in nested content block. +_Still #[ + +] emphasized._ + +--- emph-and-strong-call-in-word --- +// Inside of words can still use the functions. +P#strong[art]ly em#emph[phas]ized. + +--- emph-empty-hint --- +// Warning: 1-3 no text within underscores +// Hint: 1-3 using multiple consecutive underscores (e.g. __) has no additional effect +__ + +--- emph-double-underscore-empty-hint --- +// Warning: 1-3 no text within underscores +// Hint: 1-3 using multiple consecutive underscores (e.g. __) has no additional effect +// Warning: 13-15 no text within underscores +// Hint: 13-15 using multiple consecutive underscores (e.g. __) has no additional effect +__not italic__ + +--- emph-unclosed --- +// Error: 6-7 unclosed delimiter +#box[_Scoped] to body. + +--- emph-ends-at-parbreak --- +// Ends at paragraph break. +// Error: 1-2 unclosed delimiter +_Hello + +World + +--- emph-strong-unclosed-nested --- +// Error: 11-12 unclosed delimiter +// Error: 3-4 unclosed delimiter +#[_Cannot *be interleaved] + +--- strong-delta --- +// Adjusting the delta that strong applies on the weight. +Normal + +#set strong(delta: 300) +*Bold* + +#set strong(delta: 150) +*Medium* and *#[*Bold*]* + +--- strong-empty-hint --- +// Warning: 1-3 no text within stars +// Hint: 1-3 using multiple consecutive stars (e.g. **) has no additional effect +** + +--- strong-double-star-empty-hint --- +// Warning: 1-3 no text within stars +// Hint: 1-3 using multiple consecutive stars (e.g. **) has no additional effect +// Warning: 11-13 no text within stars +// Hint: 11-13 using multiple consecutive stars (e.g. **) has no additional effect +**not bold** diff --git a/tests/suite/model/enum.typ b/tests/suite/model/enum.typ new file mode 100644 index 00000000..57a4d7a6 --- /dev/null +++ b/tests/suite/model/enum.typ @@ -0,0 +1,156 @@ +// Test enumerations. + +--- enum-function-call --- +#enum[Embrace][Extend][Extinguish] + +--- enum-number-override-nested --- +0. Before first! +1. First. + 2. Indented + ++ Second + +--- enum-built-in-loop --- +// Test automatic numbering in summed content. +#for i in range(5) { + [+ #numbering("I", 1 + i)] +} + +--- list-mix --- +// Mix of different lists +- Bullet List ++ Numbered List +/ Term: List + +--- enum-syntax-at-start --- +// In the line. +1.2 \ +This is 0. \ +See 0.3. \ + +--- enum-syntax-edge-cases --- +// Edge cases. ++ +Empty \ ++Nope \ +a + 0. + +--- enum-number-override --- +// Test item number overriding. +1. first ++ second +5. fifth + +#enum( + enum.item(1)[First], + [Second], + enum.item(5)[Fifth] +) + +--- enum-numbering-pattern --- +// Test numbering pattern. +#set enum(numbering: "(1.a.*)") ++ First ++ Second + 2. Nested + + Deep ++ Normal + +--- enum-numbering-full --- +// Test full numbering. +#set enum(numbering: "1.a.", full: true) ++ First + + Nested + +--- enum-numbering-closure --- +// Test numbering with closure. +#enum( + start: 3, + spacing: 0.65em - 3pt, + tight: false, + numbering: n => text( + fill: (red, green, blue).at(calc.rem(n, 3)), + numbering("A", n), + ), + [Red], [Green], [Blue], [Red], +) + +--- enum-numbering-closure-nested --- +// Test numbering with closure and nested lists. +#set enum(numbering: n => super[#n]) ++ A + + B ++ C + +--- enum-numbering-closure-nested-complex --- +// Test numbering with closure and nested lists. +#set text(font: "New Computer Modern") +#set enum(numbering: (..args) => math.mat(args.pos()), full: true) ++ A + + B + + C + + D ++ E ++ F + +--- enum-numbering-pattern-empty --- +// Error: 22-24 invalid numbering pattern +#set enum(numbering: "") + +--- enum-numbering-pattern-invalid --- +// Error: 22-28 invalid numbering pattern +#set enum(numbering: "(())") + +--- enum-number-align-unaffected --- +// Alignment shouldn't affect number +#set align(horizon) + ++ ABCDEF\ GHIJKL\ MNOPQR + + INNER\ INNER\ INNER ++ BACK\ HERE + +--- enum-number-align-default --- +// Enum number alignment should be 'end' by default +1. a +10. b +100. c + +--- enum-number-align-specified --- +#set enum(number-align: start) +1. a +8. b +16. c + +--- enum-number-align-2d --- +#set enum(number-align: center + horizon) +1. #box(fill: teal, inset: 10pt )[a] +8. #box(fill: teal, inset: 10pt )[b] +16. #box(fill: teal,inset: 10pt )[c] + +--- enum-number-align-unfolded --- +// Number align option should not be affected by the context. +#set align(center) +#set enum(number-align: start) + +4. c +8. d +16. e\ f + 2. f\ g + 32. g + 64. h + +--- enum-number-align-values --- +// Test valid number align values (horizontal and vertical) +#set enum(number-align: start) +#set enum(number-align: end) +#set enum(number-align: left) +#set enum(number-align: center) +#set enum(number-align: right) +#set enum(number-align: top) +#set enum(number-align: horizon) +#set enum(number-align: bottom) + +--- issue-2530-enum-item-panic --- +// Enum item (pre-emptive) +#enum.item(none)[Hello] +#enum.item(17)[Hello] diff --git a/tests/suite/model/figure.typ b/tests/suite/model/figure.typ new file mode 100644 index 00000000..6846760f --- /dev/null +++ b/tests/suite/model/figure.typ @@ -0,0 +1,220 @@ +// Test figures. + +--- figure-basic --- +#set page(width: 150pt) +#set figure(numbering: "I") + +We can clearly see that @fig-cylinder and +@tab-complex are relevant in this context. + +#figure( + table(columns: 2)[a][b], + caption: [The basic table.], +) <tab-basic> + +#figure( + pad(y: -6pt, image("/assets/images/cylinder.svg", height: 2cm)), + caption: [The basic shapes.], + numbering: "I", +) <fig-cylinder> + +#figure( + table(columns: 3)[a][b][c][d][e][f], + caption: [The complex table.], +) <tab-complex> + +--- figure-table --- +// Testing figures with tables. +#figure( + table( + columns: 2, + [Second cylinder], + image("/assets/images/cylinder.svg"), + ), + caption: "A table containing images." +) <fig-image-in-table> + +--- figure-theorem --- +// Testing show rules with figures with a simple theorem display +#show figure.where(kind: "theorem"): it => { + let name = none + if not it.caption == none { + name = [ #emph(it.caption.body)] + } else { + name = [] + } + + let title = none + if not it.numbering == none { + title = it.supplement + if not it.numbering == none { + title += " " + it.counter.display(it.numbering) + } + } + title = strong(title) + pad( + top: 0em, bottom: 0em, + block( + fill: green.lighten(90%), + stroke: 1pt + green, + inset: 10pt, + width: 100%, + radius: 5pt, + breakable: false, + [#title#name#h(0.1em):#h(0.2em)#it.body#v(0.5em)] + ) + ) +} + +#set page(width: 150pt) +#figure( + $a^2 + b^2 = c^2$, + supplement: "Theorem", + kind: "theorem", + caption: "Pythagoras' theorem.", + numbering: "1", +) <fig-formula> + +#figure( + $a^2 + b^2 = c^2$, + supplement: "Theorem", + kind: "theorem", + caption: "Another Pythagoras' theorem.", + numbering: none, +) <fig-formula> + +#figure( + ```rust + fn main() { + println!("Hello!"); + } + ```, + caption: [Hello world in _rust_], +) + +--- figure-breakable --- +// Test breakable figures +#set page(height: 6em) +#show figure: set block(breakable: true) + +#figure(table[a][b][c][d][e], caption: [A table]) + +--- figure-caption-separator --- +// Test custom separator for figure caption +#set figure.caption(separator: [ --- ]) + +#figure( + table(columns: 2)[a][b], + caption: [The table with custom separator.], +) + +--- figure-caption-show --- +// Test figure.caption element +#show figure.caption: emph + +#figure( + [Not italicized], + caption: [Italicized], +) + +--- figure-caption-where-selector --- +// Test figure.caption element for specific figure kinds +#show figure.caption.where(kind: table): underline + +#figure( + [Not a table], + caption: [Not underlined], +) + +#figure( + table[A table], + caption: [Underlined], +) + +--- figure-and-caption-show --- +// Test creating custom figure and custom caption + +#let gap = 0.7em +#show figure.where(kind: "custom"): it => rect(inset: gap, { + align(center, it.body) + v(gap, weak: true) + line(length: 100%) + v(gap, weak: true) + align(center, it.caption) +}) + +#figure( + [A figure], + kind: "custom", + caption: [Hi], + supplement: [A], +) + +#show figure.caption: it => emph[ + #it.body + (#it.supplement + #context it.counter.display(it.numbering)) +] + +#figure( + [Another figure], + kind: "custom", + caption: [Hi], + supplement: [B], +) + +--- figure-caption-position --- +#set figure.caption(position: top) + +--- figure-caption-position-bad --- +// Error: 31-38 expected `top` or `bottom`, found horizon +#set figure.caption(position: horizon) + +--- figure-localization-fr --- +// Test French +#set text(lang: "fr") +#figure( + circle(), + caption: [Un cercle.], +) + +--- figure-localization-zh --- +// Test Chinese +#set text(lang: "zh") +#figure( + rect(), + caption: [一个矩形], +) + +--- figure-localization-ru --- +// Test Russian +#set text(lang: "ru") + +#figure( + polygon.regular(size: 1cm, vertices: 8), + caption: [Пятиугольник], +) + +--- figure-localization-gr --- +// Test Greek +#set text(lang: "gr") +#figure( + circle(), + caption: [Ένας κύκλος.], +) + +--- issue-2165-figure-caption-panic --- +#figure.caption[] + +--- issue-2328-figure-entry-panic --- +// Error: 4-43 footnote entry must have a location +// Hint: 4-43 try using a query or a show rule to customize the footnote instead +HI#footnote.entry(clearance: 2.5em)[There] + +--- issue-2530-figure-caption-panic --- +#figure(caption: [test])[].caption + +--- issue-3586-figure-caption-separator --- +// Test that figure caption separator is synthesized correctly. +#show figure.caption: c => test(c.separator, [#": "]) +#figure(table[], caption: [This is a test caption]) diff --git a/tests/suite/model/footnote.typ b/tests/suite/model/footnote.typ new file mode 100644 index 00000000..c41db577 --- /dev/null +++ b/tests/suite/model/footnote.typ @@ -0,0 +1,182 @@ +// Test footnotes. + +--- footnote-basic --- +#footnote[Hi] + +--- footnote-space-collapsing --- +// Test space collapsing before footnote. +A#footnote[A] \ +A #footnote[A] + +--- footnote-nested --- +// Test nested footnotes. +First \ +Second #footnote[A, #footnote[B, #footnote[C]]] \ +Third #footnote[D, #footnote[E]] \ +Fourth + +--- footnote-nested-same-frame --- +// Currently, numbers a bit out of order if a nested footnote ends up in the +// same frame as another one. :( +#footnote[A, #footnote[B]], #footnote[C] + +--- footnote-entry --- +// Test customization. +#show footnote: set text(red) +#show footnote.entry: set text(8pt, style: "italic") +#set footnote.entry( + indent: 0pt, + gap: 0.6em, + clearance: 0.3em, + separator: repeat[.], +) + +Beautiful footnotes. #footnote[Wonderful, aren't they?] + +--- footnote-break-across-pages --- +// LARGE +#set page(height: 200pt) + +#lorem(5) +#footnote[ // 1 + A simple footnote. + #footnote[Well, not that simple ...] // 2 +] +#lorem(15) +#footnote[Another footnote: #lorem(30)] // 3 +#lorem(15) +#footnote[My fourth footnote: #lorem(50)] // 4 +#lorem(15) +#footnote[And a final footnote.] // 5 + +--- footnote-in-columns --- +// Test footnotes in columns, even those that are not enabled via `set page`. +#set page(height: 120pt) +#align(center, strong[Title]) +#show: columns.with(2) +#lorem(3) #footnote(lorem(6)) +Hello there #footnote(lorem(2)) + +--- footnote-in-caption --- +// Test footnote in caption. +Read the docs #footnote[https://typst.app/docs]! +#figure( + image("/assets/images/graph.png", width: 70%), + caption: [ + A graph #footnote[A _graph_ is a structure with nodes and edges.] + ] +) +More #footnote[just for ...] footnotes #footnote[... testing. :)] + +--- footnote-duplicate --- +// Test duplicate footnotes. +#let lang = footnote[Languages.] +#let nums = footnote[Numbers.] + +/ "Hello": A word #lang +/ "123": A number #nums + +- "Hello" #lang +- "123" #nums + ++ "Hello" #lang ++ "123" #nums + +#table( + columns: 2, + [Hello], [A word #lang], + [123], [A number #nums], +) + +--- footnote-invariant --- +// Ensure that a footnote and the first line of its entry +// always end up on the same page. +#set page(height: 120pt) + +#lorem(13) + +There #footnote(lorem(20)) + +--- footnote-ref --- +// Test references to footnotes. +A footnote #footnote[Hi]<fn> \ +A reference to it @fn + +--- footnote-ref-multiple --- +// Multiple footnotes are refs +First #footnote[A]<fn1> \ +Second #footnote[B]<fn2> \ +First ref @fn1 \ +Third #footnote[C] \ +Fourth #footnote[D]<fn4> \ +Fourth ref @fn4 \ +Second ref @fn2 \ +Second ref again @fn2 + +--- footnote-ref-forward --- +// Forward reference +Usage @fn \ +Definition #footnote[Hi]<fn> + +--- footnote-ref-in-footnote --- +// Footnote ref in footnote +#footnote[Reference to next @fn] +#footnote[Reference to myself @fn]<fn> +#footnote[Reference to previous @fn] + +--- footnote-styling --- +// Styling +#show footnote: text.with(fill: red) +Real #footnote[...]<fn> \ +Ref @fn + +--- footnote-ref-call --- +// Footnote call with label +#footnote(<fn>) +#footnote[Hi]<fn> +#ref(<fn>) +#footnote(<fn>) + +--- footnote-in-table --- +// Test footnotes in tables. When the table spans multiple pages, the footnotes +// will all be after the table, but it shouldn't create any empty pages. +#set page(height: 100pt) + += Tables +#table( + columns: 2, + [Hello footnote #footnote[This is a footnote.]], + [This is more text], + [This cell + #footnote[This footnote is not on the same page] + breaks over multiple pages.], + image("/assets/images/tiger.jpg"), +) + +#table( + columns: 3, + ..range(1, 10) + .map(numbering.with("a")) + .map(v => upper(v) + footnote(v)) +) + +--- issue-multiple-footnote-in-one-line --- +// Test that the logic that keeps footnote entry together with +// their markers also works for multiple footnotes in a single +// line or frame (here, there are two lines, but they are one +// unit due to orphan prevention). +#set page(height: 100pt) +#v(40pt) +A #footnote[a] \ +B #footnote[b] + +--- issue-1433-footnote-in-list --- +// Test that footnotes in lists do not produce extraneous page breaks. The list +// layout itself does not currently react to the footnotes layout, weakening the +// "footnote and its entry are on the same page" invariant somewhat, but at +// least there shouldn't be extra page breaks. +#set page(height: 100pt) +#block(height: 50pt, width: 100%, fill: aqua) + +- #footnote[1] +- #footnote[2] diff --git a/tests/suite/model/heading.typ b/tests/suite/model/heading.typ new file mode 100644 index 00000000..5d50eeee --- /dev/null +++ b/tests/suite/model/heading.typ @@ -0,0 +1,80 @@ +// Test headings. + +--- heading-basic --- +// Different number of equals signs. + += Level 1 +== Level 2 +=== Level 3 + +// After three, it stops shrinking. +=========== Level 11 + +--- heading-syntax-at-start --- +// Heading vs. no heading. + +// Parsed as headings if at start of the context. +/**/ = Level 1 +#[== Level 2] +#box[=== Level 3] + +// Not at the start of the context. +No = heading + +// Escaped. +\= No heading + +--- heading-block --- +// Blocks can continue the heading. + += #[This +is +multiline. +] + += This + is not. + +--- heading-show-where --- +// Test styling. +#show heading.where(level: 5): it => block( + text(font: "Roboto", fill: eastern, it.body + [!]) +) + += Heading +===== Heading 🌍 +#heading(level: 5)[Heading] + +--- heading-offset --- +// Test setting the starting offset. +#set heading(numbering: "1.1") +#show heading.where(level: 2): set text(blue) += Level 1 + +#heading(depth: 1)[We're twins] +#heading(level: 1)[We're twins] + +== Real level 2 + +#set heading(offset: 1) += Fake level 2 +== Fake level 3 + +--- heading-offset-and-level --- +// Passing level directly still overrides all other set values +#set heading(numbering: "1.1", offset: 1) +#heading(level: 1)[Still level 1] + +--- heading-syntax-edge-cases --- +// Edge cases. +#set heading(numbering: "1.") += +Not in heading +=Nope + +--- heading-numbering-hint --- += Heading <intro> + +// Error: 1:20-1:26 cannot reference heading without numbering +// Hint: 1:20-1:26 you can enable heading numbering with `#set heading(numbering: "1.")` +Can not be used as @intro diff --git a/tests/suite/model/link.typ b/tests/suite/model/link.typ new file mode 100644 index 00000000..27afd53c --- /dev/null +++ b/tests/suite/model/link.typ @@ -0,0 +1,77 @@ +// Test hyperlinking. + +--- link-basic --- +// Link syntax. +https://example.com/ + +// Link with body. +#link("https://typst.org/")[Some text text text] + +// With line break. +This link appears #link("https://google.com/")[in the middle of] a paragraph. + +// Certain prefixes are trimmed when using the `link` function. +Contact #link("mailto:hi@typst.app") or +call #link("tel:123") for more information. + +--- link-trailing-period --- +// Test that the period is trimmed. +#show link: underline +https://a.b.?q=%10#. \ +Wahttp://link \ +Nohttps:\//link \ +Nohttp\://comment + +--- link-bracket-balanced --- +// Verify that brackets are included in links. +https://[::1]:8080/ \ +https://example.com/(paren) \ +https://example.com/#(((nested))) \ + +--- link-bracket-unbalanced-closing --- +// Check that unbalanced brackets are not included in links. +#[https://example.com/] \ +https://example.com/) + +--- link-bracket-unbalanced-opening --- +// Verify that opening brackets without closing brackets throw an error. +// Error: 1-22 automatic links cannot contain unbalanced brackets, use the `link` function instead +https://exam(ple.com/ + +--- link-show --- +// Styled with underline and color. +#show link: it => underline(text(fill: rgb("283663"), it)) +You could also make the +#link("https://html5zombo.com/")[link look way more typical.] + +--- link-transformed --- +// Transformed link. +#set page(height: 60pt) +#let mylink = link("https://typst.org/")[LINK] +My cool #box(move(dx: 0.7cm, dy: 0.7cm, rotate(10deg, scale(200%, mylink)))) + +--- link-on-block --- +// Link containing a block. +#link("https://example.com/", block[ + My cool rhino + #box(move(dx: 10pt, image("/assets/images/rhino.png", width: 1cm))) +]) + +--- link-to-page --- +// Link to page one. +#link((page: 1, x: 10pt, y: 20pt))[Back to the start] + +--- link-to-label --- +// Test link to label. +Text <hey> +#link(<hey>)[Go to text.] + +--- link-to-label-missing --- +// Error: 2-20 label `<hey>` does not exist in the document +#link(<hey>)[Nope.] + +--- link-to-label-duplicate --- +Text <hey> +Text <hey> +// Error: 2-20 label `<hey>` occurs multiple times in the document +#link(<hey>)[Nope.] diff --git a/tests/suite/model/list.typ b/tests/suite/model/list.typ new file mode 100644 index 00000000..e37fa65d --- /dev/null +++ b/tests/suite/model/list.typ @@ -0,0 +1,147 @@ +// Test bullet lists. + +--- list-basic --- +_Shopping list_ +#list[Apples][Potatoes][Juice] + +--- list-nested --- +- First level. + + - Second level. + There are multiple paragraphs. + + - Third level. + + Still the same bullet point. + + - Still level 2. + +- At the top. + +--- list-content-block --- +- Level 1 + - Level #[ +2 through content block +] + +--- list-top-level-indent --- + - Top-level indent +- is fine. + +--- list-indent-specifics --- + - A + - B + - C +- D + +--- list-tabs --- +// This works because tabs are used consistently. + - A with 1 tab + - B with 2 tabs + +--- list-mixed-tabs-and-spaces --- +// This doesn't work because of mixed tabs and spaces. + - A with 2 spaces + - B with 2 tabs + +--- list-syntax-edge-cases --- +// Edge cases. +- +Not in list +-Nope + +--- list-marker-align-unaffected --- +// Alignment shouldn't affect marker +#set align(horizon) + +- ABCDEF\ GHIJKL\ MNOPQR + +--- list-marker-dash --- +// Test en-dash. +#set list(marker: [--]) +- A +- B + +--- list-marker-cycle --- +// Test that items are cycled. +#set list(marker: ([--], [•])) +- A + - B + - C + +--- list-marker-closure --- +// Test function. +#set list(marker: n => if n == 1 [--] else [•]) +- A +- B + - C + - D + - E +- F + +--- list-marker-bare-hyphen --- +// Test that bare hyphen doesn't lead to cycles and crashes. +#set list(marker: [-]) +- Bare hyphen is +- a bad marker + +--- list-marker-array-empty --- +// Error: 19-21 array must contain at least one marker +#set list(marker: ()) + +--- list-attached --- +// Test basic attached list. +Attached to: +- the bottom +- of the paragraph + +Next paragraph. + +--- list-attached-above-spacing --- +// Test that attached list isn't affected by block spacing. +#show list: set block(above: 100pt) +Hello +- A +World +- B + +--- list-non-attached-followed-by-attached --- +// Test non-attached list followed by attached list, +// separated by only word. +Hello + +- A + +World +- B + +--- list-tight-non-attached-tight --- +// Test non-attached tight list. +#set block(spacing: 15pt) +Hello +- A +World + +- B +- C + +More. + +--- list-wide-cannot-attach --- +// Test that wide lists cannot be ... +#set block(spacing: 15pt) +Hello +- A + +- B +World + +--- list-wide-really-cannot-attach --- +// ... even if forced to. +Hello +#list(tight: false)[A][B] +World + +--- issue-2530-list-item-panic --- +// List item (pre-emptive) +#list.item[Hello] diff --git a/tests/suite/model/numbering.typ b/tests/suite/model/numbering.typ new file mode 100644 index 00000000..c2de1e05 --- /dev/null +++ b/tests/suite/model/numbering.typ @@ -0,0 +1,103 @@ +// Test integrated numbering patterns. + +--- numbering-symbol-and-roman --- +#for i in range(0, 9) { + numbering("*", i) + [ and ] + numbering("I.a", i, i) + [ for #i \ ] +} + +--- numbering-latin --- +#for i in range(0, 4) { + numbering("A", i) + [ for #i \ ] +} +... \ +#for i in range(26, 30) { + numbering("A", i) + [ for #i \ ] +} +... \ +#for i in range(702, 706) { + numbering("A", i) + [ for #i \ ] +} + +--- numbering-hebrew --- +#set text(lang: "he") +#for i in range(9, 21, step: 2) { + numbering("א.", i) + [ עבור #i \ ] +} + +--- numbering-chinese --- +#set text(lang: "zh", font: ("Linux Libertine", "Noto Serif CJK SC")) +#for i in range(9, 21, step: 2){ + numbering("一", i) + [ and ] + numbering("壹", i) + [ for #i \ ] +} + +--- numbering-japanese-iroha --- +#set text(lang: "ja", font: ("Linux Libertine", "Noto Serif CJK JP")) +#for i in range(0, 4) { + numbering("イ", i) + [ (or ] + numbering("い", i) + [) for #i \ ] +} +... \ +#for i in range(47, 51) { + numbering("イ", i) + [ (or ] + numbering("い", i) + [) for #i \ ] +} +... \ +#for i in range(2256, 2260) { + numbering("イ", i) + [ for #i \ ] +} + +--- numbering-korean --- +#set text(lang: "ko", font: ("Linux Libertine", "Noto Serif CJK KR")) +#for i in range(0, 4) { + numbering("가", i) + [ (or ] + numbering("ㄱ", i) + [) for #i \ ] +} +... \ +#for i in range(47, 51) { + numbering("가", i) + [ (or ] + numbering("ㄱ", i) + [) for #i \ ] +} +... \ +#for i in range(2256, 2260) { + numbering("ㄱ", i) + [ for #i \ ] +} + +--- numbering-japanese-aiueo --- +#set text(lang: "jp", font: ("Linux Libertine", "Noto Serif CJK JP")) +#for i in range(0, 9) { + numbering("あ", i) + [ and ] + numbering("I.あ", i, i) + [ for #i \ ] +} + +#for i in range(0, 9) { + numbering("ア", i) + [ and ] + numbering("I.ア", i, i) + [ for #i \ ] +} + +--- numbering-negative --- +// Error: 17-19 number must be at least zero +#numbering("1", -1) diff --git a/tests/suite/model/outline.typ b/tests/suite/model/outline.typ new file mode 100644 index 00000000..d8fc1a43 --- /dev/null +++ b/tests/suite/model/outline.typ @@ -0,0 +1,176 @@ +--- outline --- +// LARGE +#set page("a7", margin: 20pt, numbering: "1") +#set heading(numbering: "(1/a)") +#show heading.where(level: 1): set text(12pt) +#show heading.where(level: 2): set text(10pt) +#set math.equation(numbering: "1") + +#outline() +#outline(title: [Figures], target: figure) +#outline(title: [Equations], target: math.equation) + += Introduction +#lorem(12) + += Analysis +#lorem(10) + +#[ + #set heading(outlined: false) + == Methodology + #lorem(6) +] + +== Math +$x$ is a very useful constant. See it in action: +$ x = x $ + +== Interesting figures +#figure(rect[CENSORED], kind: image, caption: [A picture showing a programmer at work.]) +#figure(table[1x1], caption: [A very small table.]) + +== Programming +```rust +fn main() { + panic!("in the disco"); +} +``` + +==== Deep Stuff +Ok ... + +// Ensure 'bookmarked' option doesn't affect the outline +#set heading(numbering: "(I)", bookmarked: false) + += #text(blue)[Sum]mary +#lorem(10) + +--- outline-indent-numbering --- +// LARGE +// With heading numbering +#set page(width: 200pt) +#set heading(numbering: "1.a.") +#show heading: none +#set outline(fill: none) + +#context test(outline.indent, none) +#outline(indent: false) +#outline(indent: true) +#outline(indent: none) +#outline(indent: auto) +#outline(indent: 2em) +#outline(indent: n => ([-], [], [==], [====]).at(n)) + += About ACME Corp. +== History +== Products +=== Categories +==== General + +--- outline-indent-no-numbering --- +// Without heading numbering +#set page(width: 200pt) +#show heading: none +#set outline(fill: none) + +#outline(indent: false) +#outline(indent: true) +#outline(indent: none) +#outline(indent: auto) +#outline(indent: n => 2em * n) + += About +== History + +--- outline-indent-bad-type --- +// Error: 2-35 expected relative length or content, found dictionary +#outline(indent: n => (a: "dict")) + += Heading + +--- outline-first-line-indent --- +#set par(first-line-indent: 1.5em) +#set heading(numbering: "1.1.a.") +#show outline.entry.where(level: 1): it => { + v(0.5em, weak: true) + strong(it) +} + +#outline() + += Introduction += Background +== History +== State of the Art += Analysis +== Setup + +--- outline-entry --- +#set page(width: 150pt) +#set heading(numbering: "1.") + +#show outline.entry.where( + level: 1 +): it => { + v(12pt, weak: true) + strong(it) +} + +#outline(indent: auto) + +#set text(8pt) +#show heading: set block(spacing: 0.65em) + += Introduction += Background +== History +== State of the Art += Analysis +== Setup + +--- outline-entry-complex --- +#set page(width: 150pt, numbering: "I", margin: (bottom: 20pt)) +#set heading(numbering: "1.") +#show outline.entry.where(level: 1): it => [ + #let loc = it.element.location() + #let num = numbering(loc.page-numbering(), ..counter(page).at(loc)) + #emph(link(loc, it.body)) + #text(luma(100), box(width: 1fr, repeat[#it.fill.body;·])) + #link(loc, num) +] + +#counter(page).update(3) +#outline(indent: auto, fill: repeat[--]) + +#set text(8pt) +#show heading: set block(spacing: 0.65em) + += Top heading +== Not top heading +=== Lower heading +=== Lower too +== Also not top + +#pagebreak() +#set page(numbering: "1") + += Another top heading +== Middle heading +=== Lower heading + +--- outline-bad-element --- +// Error: 2-27 cannot outline metadata +#outline(target: metadata) +#metadata("hello") + +--- issue-2530-outline-entry-panic-text --- +// Outline entry (pre-emptive) +// Error: 2-48 cannot outline text +#outline.entry(1, [Hello], [World!], none, [1]) + +--- issue-2530-outline-entry-panic-heading --- +// Outline entry (pre-emptive, improved error) +// Error: 2-55 heading must have a location +// Hint: 2-55 try using a query or a show rule to customize the outline.entry instead +#outline.entry(1, heading[Hello], [World!], none, [1]) diff --git a/tests/suite/model/par.typ b/tests/suite/model/par.typ new file mode 100644 index 00000000..65779f6a --- /dev/null +++ b/tests/suite/model/par.typ @@ -0,0 +1,78 @@ +// Test configuring paragraph properties. + +--- par-basic --- +#set page(width: 250pt, height: 120pt) + +But, soft! what light through yonder window breaks? It is the east, and Juliet +is the sun. Arise, fair sun, and kill the envious moon, Who is already sick and +pale with grief, That thou her maid art far more fair than she: Be not her maid, +since she is envious; Her vestal livery is but sick and green And none but fools +do wear it; cast it off. It is my lady, O, it is my love! O, that she knew she +were! She speaks yet she says nothing: what of that? Her eye discourses; I will +answer it. + +I am too bold, 'tis not to me she speaks: Two of the fairest stars in all the +heaven, Having some business, do entreat her eyes To twinkle in their spheres +till they return. What if her eyes were there, they in her head? The brightness +of her cheek would shame those stars, As daylight doth a lamp; her eyes in +heaven Would through the airy region stream so bright That birds would sing and +think it were not night. See, how she leans her cheek upon her hand! O, that I +were a glove upon that hand, That I might touch that cheek! + +--- par-leading-and-block-spacing --- +// Test changing leading and spacing. +#set block(spacing: 1em) +#set par(leading: 2pt) +But, soft! what light through yonder window breaks? + +It is the east, and Juliet is the sun. + +--- par-first-line-indent --- +#set par(first-line-indent: 12pt, leading: 5pt) +#set block(spacing: 5pt) +#show heading: set text(size: 10pt) + +The first paragraph has no indent. + +But the second one does. + +#box(image("/assets/images/tiger.jpg", height: 6pt)) +starts a paragraph, also with indent. + +#align(center, image("/assets/images/rhino.png", width: 1cm)) + += Headings +- And lists. +- Have no indent. + + Except if you have another paragraph in them. + +#set text(8pt, lang: "ar", font: ("Noto Sans Arabic", "Linux Libertine")) +#set par(leading: 8pt) + += Arabic +دع النص يمطر عليك + +ثم يصبح النص رطبًا وقابل للطرق ويبدو المستند رائعًا. + +--- par-spacing-and-first-line-indent --- +// This is madness. +#set par(first-line-indent: 12pt) +Why would anybody ever ... + +... want spacing and indent? + +--- par-hanging-indent --- +// Test hanging indent. +#set par(hanging-indent: 15pt, justify: true) +#lorem(10) + +--- par-hanging-indent-manual-linebreak --- +#set par(hanging-indent: 1em) +Welcome \ here. Does this work well? + +--- par-hanging-indent-rtl --- +#set par(hanging-indent: 2em) +#set text(dir: rtl) +لآن وقد أظلم الليل وبدأت النجوم +تنضخ وجه الطبيعة التي أعْيَتْ من طول ما انبعثت في النهار diff --git a/tests/suite/model/quote.typ b/tests/suite/model/quote.typ new file mode 100644 index 00000000..446784ee --- /dev/null +++ b/tests/suite/model/quote.typ @@ -0,0 +1,86 @@ +// Test the quote element. + +--- quote-dir-author-pos --- +// Text direction affects author positioning +And I quote: #quote(attribution: [René Descartes])[cogito, ergo sum]. + +#set text(lang: "ar") +#quote(attribution: [عالم])[مرحبًا] + +--- quote-dir-align --- +// Text direction affects block alignment +#set quote(block: true) +#quote(attribution: [René Descartes])[cogito, ergo sum] + +#set text(lang: "ar") +#quote(attribution: [عالم])[مرحبًا] + +--- quote-block-spacing --- +// Spacing with other blocks +#set quote(block: true) +#set text(8pt) + +#lorem(10) +#quote(lorem(10)) +#lorem(10) + +--- quote-inline --- +// Inline citation +#set text(8pt) +#quote(attribution: <tolkien54>)[In a hole in the ground there lived a hobbit.] + +#set text(0pt) +#bibliography("/assets/bib/works.bib") + +--- quote-cite-format-label-or-numeric --- +// Citation-format: label or numeric +#set text(8pt) +#set quote(block: true) +#quote(attribution: <tolkien54>)[In a hole in the ground there lived a hobbit.] + +#set text(0pt) +#bibliography("/assets/bib/works.bib", style: "ieee") + +--- quote-cite-format-note --- +// Citation-format: note +#set text(8pt) +#set quote(block: true) +#quote(attribution: <tolkien54>)[In a hole in the ground there lived a hobbit.] + +#set text(0pt) +#bibliography("/assets/bib/works.bib", style: "chicago-notes") + +--- quote-cite-format-author-date --- +// Citation-format: author-date or author +#set text(8pt) +#set quote(block: true) +#quote(attribution: <tolkien54>)[In a hole in the ground there lived a hobbit.] + +#set text(0pt) +#bibliography("/assets/bib/works.bib", style: "apa") + +--- quote-nesting --- +// Test quote selection. +#set page(width: auto) +#set text(lang: "en") +=== EN +#quote[An apostroph'] \ +#quote[A #quote[nested] quote] \ +#quote[A #quote[very #quote[nested]] quote] + +#set text(lang: "de") +=== DE +#quote[Satz mit Apostroph'] \ +#quote[Satz mit #quote[Zitat]] \ +#quote[A #quote[very #quote[nested]] quote] + +#set smartquote(alternative: true) +=== DE Alternative +#quote[Satz mit Apostroph'] \ +#quote[Satz mit #quote[Zitat]] \ +#quote[A #quote[very #quote[nested]] quote] + +--- quote-nesting-custom --- +// With custom quotes. +#set smartquote(quotes: (single: ("<", ">"), double: ("(", ")"))) +#quote[A #quote[nested] quote] diff --git a/tests/suite/model/ref.typ b/tests/suite/model/ref.typ new file mode 100644 index 00000000..200f40aa --- /dev/null +++ b/tests/suite/model/ref.typ @@ -0,0 +1,56 @@ +// Test references. + +--- ref-basic --- +#set heading(numbering: "1.") + += Introduction <intro> +See @setup. + +== Setup <setup> +As seen in @intro, we proceed. + +--- ref-label-missing --- +// Error: 1-5 label `<foo>` does not exist in the document +@foo + +--- ref-label-duplicate --- += First <foo> += Second <foo> + +// Error: 1-5 label `<foo>` occurs multiple times in the document +@foo + +--- ref-supplements --- +#set heading(numbering: "1.", supplement: [Chapter]) +#set math.equation(numbering: "(1)", supplement: [Eq.]) + += Intro +#figure( + image("/assets/images/cylinder.svg", height: 1cm), + caption: [A cylinder.], + supplement: "Fig", +) <fig1> + +#figure( + image("/assets/images/tiger.jpg", height: 1cm), + caption: [A tiger.], + supplement: "Tig", +) <fig2> + +$ A = 1 $ <eq1> + +#set math.equation(supplement: none) +$ A = 1 $ <eq2> + +@fig1, @fig2, @eq1, (@eq2) + +#set ref(supplement: none) +@fig1, @fig2, @eq1, @eq2 + +--- ref-ambigious --- +// Test ambiguous reference. += Introduction <arrgh> + +// Error: 1-7 label occurs in the document and its bibliography +@arrgh +#bibliography("/assets/bib/works.bib") diff --git a/tests/suite/model/terms.typ b/tests/suite/model/terms.typ new file mode 100644 index 00000000..6a08b923 --- /dev/null +++ b/tests/suite/model/terms.typ @@ -0,0 +1,77 @@ +// Test term list. + +--- terms-constructor --- +// Test with constructor. +#terms( + ([One], [First]), + ([Two], [Second]), +) + +--- terms-built-in-loop --- +// Test joining. +#for word in lorem(4).split().map(s => s.trim(".")) [ + / #word: Latin stuff. +] + +--- terms-multiline --- +// Test multiline. +#set text(8pt) + +/ Fruit: A tasty, edible thing. +/ Veggie: + An important energy source + for vegetarians. + + And healthy! + +--- terms-style-change-interrupted --- +// Test style change. +#set text(8pt) +/ First list: #lorem(6) + +#set terms(hanging-indent: 30pt) +/ Second list: #lorem(5) + +--- terms-rtl --- +// Test RTL. +#set text(8pt, dir: rtl) + +/ פרי: דבר טעים, אכיל. ומקור אנרגיה חשוב לצמחונים. + +--- terms-grid --- +// Test grid like show rule. +#show terms: it => table( + columns: 2, + inset: 3pt, + ..it.children.map(v => (emph(v.term), v.description)).flatten(), +) + +/ A: One letter +/ BB: Two letters +/ CCC: Three letters + +--- terms-syntax-edge-cases --- +/ Term: +Not in list +/Nope + +--- terms-missing-colon --- +// Error: 8 expected colon +/ Hello + +--- issue-1050-terms-indent --- +#set page(width: 200pt) +#set par(first-line-indent: 0.5cm) + +- #lorem(10) +- #lorem(10) + ++ #lorem(10) ++ #lorem(10) + +/ Term 1: #lorem(10) +/ Term 2: #lorem(10) + +--- issue-2530-term-item-panic --- +// Term item (pre-emptive) +#terms.item[Hello][World!] diff --git a/tests/suite/playground.typ b/tests/suite/playground.typ new file mode 100644 index 00000000..1af70bea --- /dev/null +++ b/tests/suite/playground.typ @@ -0,0 +1 @@ +--- playground --- diff --git a/tests/suite/scripting/blocks.typ b/tests/suite/scripting/blocks.typ new file mode 100644 index 00000000..f139b8c6 --- /dev/null +++ b/tests/suite/scripting/blocks.typ @@ -0,0 +1,143 @@ +// Test code blocks. + +--- code-block-basic-syntax --- + +// Evaluates to join of none, [My ] and the two loop bodies. +#{ + let parts = ("my fri", "end.") + [Hello, ] + for s in parts [#s] +} + +// Evaluates to join of the content and strings. +#{ + [How] + if true { + " are" + } + [ ] + if false [Nope] + [you] + "?" +} + +--- code-block-empty --- +// Nothing evaluates to none. +#test({}, none) + +--- code-block-let --- +// Let evaluates to none. +#test({ let v = 0 }, none) + +--- code-block-single-expression --- +// Evaluates to single expression. +#test({ "hello" }, "hello") + +--- code-block-multiple-expressions-single-line --- +// Evaluates to string. +#test({ let x = "m"; x + "y" }, "my") + +--- code-block-join-let-with-expression --- +// Evaluated to int. +#test({ + let x = 1 + let y = 2 + x + y +}, 3) + +--- code-block-join-expression-with-none --- +// String is joined with trailing none, evaluates to string. +#test({ + type("") + none +}, str) + +--- code-block-join-int-with-content --- +// Some things can't be joined. +#{ + [A] + // Error: 3-4 cannot join content with integer + 1 + [B] +} + +--- code-block-scope-in-markup --- +// Block directly in markup also creates a scope. +#{ let x = 1 } + +// Error: 7-8 unknown variable: x +#test(x, 1) + +--- code-block-scope-in-let --- +// Block in expression does create a scope. +#let a = { + let b = 1 + b +} + +#test(a, 1) + +// Error: 3-4 unknown variable: b +#{b} + +--- code-block-double-scope --- +// Double block creates a scope. +#{{ + import "module.typ": b + test(b, 1) +}} + +// Error: 2-3 unknown variable: b +#b + +--- code-block-nested-scopes --- +// Multiple nested scopes. +#{ + let a = "a1" + { + let a = "a2" + { + test(a, "a2") + let a = "a3" + test(a, "a3") + } + test(a, "a2") + } + test(a, "a1") +} + +--- code-block-multiple-literals-without-semicolon --- +// Multiple unseparated expressions in one line. +// Error: 4 expected semicolon or line break +#{1 2} + +--- code-block-multiple-expressions-without-semicolon --- +// Error: 13 expected semicolon or line break +// Error: 23 expected semicolon or line break +#{let x = -1 let y = 3 x + y} + +--- code-block-incomplete-expressions --- +#{ + // Error: 7-10 expected pattern, found string + for "v" + + // Error: 8 expected keyword `in` + // Error: 22 expected block + for v let z = 1 + 2 + + z +} + +--- code-block-unclosed --- +// Error: 2-3 unclosed delimiter +#{ + +--- code-block-unopened --- +// Error: 2-3 unexpected closing brace +#} + +--- content-block-in-markup-scope --- +// Content blocks also create a scope. +#[#let x = 1] + +// Error: 2-3 unknown variable: x +#x diff --git a/tests/suite/scripting/call.typ b/tests/suite/scripting/call.typ new file mode 100644 index 00000000..e79fc949 --- /dev/null +++ b/tests/suite/scripting/call.typ @@ -0,0 +1,200 @@ +// Test function calls. + +--- call-basic --- + +// Omitted space. +#let f() = {} +#[#f()*Bold*] + +// Call return value of function with body. +#let f(x, body) = (y) => [#x] + body + [#y] +#f(1)[2](3) + +// Don't parse this as a function. +#test (it) + +#let f(body) = body +#f[A] +#f()[A] +#f([A]) + +#let g(a, b) = a + b +#g[A][B] +#g([A], [B]) +#g()[A][B] + +--- call-aliased-function --- +// Call function assigned to variable. +#let alias = type +#test(alias(alias), type) + +--- call-complex-callee-expression --- +// Callee expressions. +#{ + // Wrapped in parens. + test((type)("hi"), str) + + // Call the return value of a function. + let adder(dx) = x => x + dx + test(adder(2)(5), 7) +} + +--- call-bad-type-bool-literal --- +// Error: 2-6 expected function, found boolean +#true() + +--- call-bad-type-string-var --- +#let x = "x" + +// Error: 2-3 expected function, found string +#x() + +--- call-bad-type-int-expr --- +#let f(x) = x + +// Error: 2-6 expected function, found integer +#f(1)(2) + +--- call-bad-type-content-expr --- +#let f(x) = x + +// Error: 2-6 expected function, found content +#f[1](2) + +--- call-args-trailing-comma --- +// Trailing comma. +#test(1 + 1, 2,) + +--- call-args-duplicate --- +// Error: 26-30 duplicate argument: font +#set text(font: "Arial", font: "Helvetica") + +--- call-args-bad-positional-as-named --- +// Error: 4-15 the argument `amount` is positional +// Hint: 4-15 try removing `amount:` +#h(amount: 0.5) + +--- call-args-bad-colon --- +// Error: 7-8 unexpected colon +#func(:) + +--- call-args-bad-token --- +// Error: 10-12 unexpected end of block comment +#func(a:1*/) + +--- call-args-missing-comma --- +// Error: 8 expected comma +#func(1 2) + +--- call-args-bad-name-and-incomplete-pair --- +// Error: 7-8 expected identifier, found integer +// Error: 9 expected expression +#func(1:) + +--- call-args-bad-name-int --- +// Error: 7-8 expected identifier, found integer +#func(1:2) + +--- call-args-bad-name-string --- +// Error: 7-12 expected identifier, found string +#func("abc": 2) + +--- call-args-bad-name-group --- +// Error: 7-10 expected identifier, found group +#func((x):1) + +--- call-args-lone-underscore --- +// Test that lone underscore works. +#test((1, 2, 3).map(_ => {}).len(), 3) + +--- call-args-spread-override --- +// Test standard argument overriding. +#{ + let f(style: "normal", weight: "regular") = { + "(style: " + style + ", weight: " + weight + ")" + } + + let myf(..args) = f(weight: "bold", ..args) + test(myf(), "(style: normal, weight: bold)") + test(myf(weight: "black"), "(style: normal, weight: black)") + test(myf(style: "italic"), "(style: italic, weight: bold)") +} + +--- call-args-spread-forward --- +// Test multiple calls. +#{ + let f(b, c: "!") = b + c + let g(a, ..sink) = a + f(..sink) + test(g("a", "b", c: "c"), "abc") +} + +--- call-args-spread-type-repr --- +// Test doing things with arguments. +#{ + let save(..args) = { + test(type(args), arguments) + test(repr(args), "(three: true, 1, 2)") + } + + save(1, 2, three: true) +} + +--- call-args-spread-array-and-dict --- +// Test spreading array and dictionary. +#{ + let more = (3, -3, 6, 10) + test(calc.min(1, 2, ..more), -3) + test(calc.max(..more, 9), 10) + test(calc.max(..more, 11), 11) +} + +#{ + let more = (c: 3, d: 4) + let tostr(..args) = repr(args) + test(tostr(a: 1, ..more, b: 2), "(a: 1, c: 3, d: 4, b: 2)") +} + +--- call-args-spread-none --- +// None is spreadable. +#let f() = none +#f(..none) +#f(..if false {}) +#f(..for x in () []) + +--- call-args-spread-string-invalid --- +// Error: 11-19 cannot spread string +#calc.min(.."nope") + +--- call-args-content-block-unclosed --- +// Error: 6-7 unclosed delimiter +#func[`a]` + +--- issue-886-args-sink --- +// Test bugs with argument sinks. +#let foo(..body) = repr(body.pos()) +#foo(a: "1", b: "2", 1, 2, 3, 4, 5, 6) + +--- issue-3144-unexpected-arrow --- +#let f(a: 10) = a(1) + 1 +#test(f(a: _ => 5), 6) + +--- issue-3502-space-and-comments-around-destructuring-colon --- +#let ( key : /* hi */ binding ) = ( key: "ok" ) +#test(binding, "ok") + +--- issue-3502-space-around-dict-colon --- +#test(( key : "value" ).key, "value") + +--- issue-3502-space-around-param-colon --- +// Test that a space after a named parameter is permissible. +#let f( param : v ) = param +#test(f( param /* ok */ : 2 ), 2) + +--- call-args-unclosed --- +// Error: 7-8 unclosed delimiter +#{func(} + +--- call-args-unclosed-string --- +// Error: 6-7 unclosed delimiter +// Error: 1:7-2:1 unclosed string +#func("] diff --git a/tests/suite/scripting/closure.typ b/tests/suite/scripting/closure.typ new file mode 100644 index 00000000..e3677d33 --- /dev/null +++ b/tests/suite/scripting/closure.typ @@ -0,0 +1,223 @@ +// Test closures. + +--- closure-without-params-non-atomic --- +// Don't parse closure directly in content. + +#let x = "x" + +// Should output `x => y`. +#x => y + +--- closure-without-captures --- +// Basic closure without captures. +#{ + let adder = (x, y) => x + y + test(adder(2, 3), 5) +} + +--- closure-as-arg --- +// Pass closure as argument and return closure. +// Also uses shorthand syntax for a single argument. +#{ + let chain = (f, g) => (x) => f(g(x)) + let f = x => x + 1 + let g = x => 2 * x + let h = chain(f, g) + test(h(2), 5) +} + +--- closure-capture-from-popped-stack-frame --- +// Capture environment. +#{ + let mark = "!" + let greet = { + let hi = "Hi" + name => { + hi + ", " + name + mark + } + } + + test(greet("Typst"), "Hi, Typst!") + + // Changing the captured variable after the closure definition has no effect. + mark = "?" + test(greet("Typst"), "Hi, Typst!") +} + +--- closure-shadows-outer-var --- +// Redefined variable. +#{ + let x = 1 + let f() = { + let x = x + 2 + x + } + test(f(), 3) +} + +--- closure-shadows-outer-var-import --- +// Import bindings. +#{ + let b = "module.typ" + let f() = { + import b: b + b + } + test(f(), 1) +} + +--- closure-shadows-outer-var-for-loop --- +// For loop bindings. +#{ + let v = (1, 2, 3) + let f() = { + let s = 0 + for v in v { s += v } + s + } + test(f(), 6) +} + +--- closure-let-basic --- +// Let + closure bindings. +#{ + let g = "hi" + let f() = { + let g() = "bye" + g() + } + test(f(), "bye") +} + +--- closure-let-args --- +// Parameter bindings. +#{ + let x = 5 + let g() = { + let f(x, y: x) = x + y + f + } + + test(g()(8), 13) +} + +--- closure-bad-capture --- +// Don't leak environment. +#{ + // Error: 16-17 unknown variable: x + let func() = x + let x = "hi" + func() +} + +--- closure-missing-arg-positional --- +// Too few arguments. +#{ + let types(x, y) = "[" + str(type(x)) + ", " + str(type(y)) + "]" + test(types(14%, 12pt), "[ratio, length]") + + // Error: 8-21 missing argument: y + test(types("nope"), "[string, none]") +} + +--- closure-too-many-args-positional --- +// Too many arguments. +#{ + let f(x) = x + 1 + + // Error: 8-13 unexpected argument + f(1, "two", () => x) +} + +--- closure-capture-in-lvalue --- +// Mutable method with capture in argument. +#let x = "b" +#let f() = { + let a = (b: 5) + a.at(x) = 10 + a +} +#f() + +--- closure-capture-mutate --- +#let x = () +#let f() = { + // Error: 3-4 variables from outside the function are read-only and cannot be modified + x.at(1) = 2 +} +#f() + +--- closure-named-args-basic --- +// Named arguments. +#{ + let greet(name, birthday: false) = { + if birthday { "Happy Birthday, " } else { "Hey, " } + name + "!" + } + + test(greet("Typst"), "Hey, Typst!") + test(greet("Typst", birthday: true), "Happy Birthday, Typst!") + + // Error: 23-35 unexpected argument: whatever + test(greet("Typst", whatever: 10)) +} + +--- closure-args-sink --- +// Parameter unpacking. +#let f((a, b), ..c) = (a, b, c) +#test(f((1, 2), 3, 4), (1, 2, (3, 4))) + +#let f((k: a, b), c: 3, (d,)) = (a, b, c, d) +#test(f((k: 1, b: 2), (4,)), (1, 2, 3, 4)) + +// Error: 8-14 expected identifier, found destructuring pattern +#let f((a, b): 0) = none + +// Error: 10-19 expected pattern, found array +#let f(..(a, b: c)) = none + +// Error: 10-16 expected pattern, found array +#let f(..(a, b)) = none + +--- closure-param-duplicate-positional --- +// Error: 11-12 duplicate parameter: x +#let f(x, x) = none + +--- closure-body-multiple-expressions --- +// Error: 21 expected comma +// Error: 22-23 expected pattern, found integer +// Error: 24-25 unexpected plus +// Error: 26-27 expected pattern, found integer +#let f = (x: () => 1 2 + 3) => 4 + +--- closure-param-duplicate-mixed --- +// Error: 14-15 duplicate parameter: a +// Error: 23-24 duplicate parameter: b +// Error: 35-36 duplicate parameter: b +#let f(a, b, a: none, b: none, c, b) = none + +--- closure-param-duplicate-spread --- +// Error: 13-14 duplicate parameter: a +#let f(a, ..a) = none + +--- closure-pattern-bad-string --- +// Error: 7-14 expected pattern, found string +#((a, "named": b) => none) + +--- closure-let-pattern-bad-string --- +// Error: 10-15 expected pattern, found string +#let foo("key": b) = key + +--- closure-param-keyword --- +// Error: 10-14 expected pattern, found `none` +// Hint: 10-14 keyword `none` is not allowed as an identifier; try `none_` instead +#let foo(none: b) = key + +--- closure-param-named-underscore --- +// Error: 10-11 expected identifier, found underscore +#let foo(_: 3) = none + +--- issue-non-atomic-closure --- +// Ensure that we can't have non-atomic closures. +#let x = 1 +#let c = [#(x) => (1, 2)] +#test(c.children.last(), [(1, 2)])) diff --git a/tests/suite/scripting/destructuring.typ b/tests/suite/scripting/destructuring.typ new file mode 100644 index 00000000..0a3c1c54 --- /dev/null +++ b/tests/suite/scripting/destructuring.typ @@ -0,0 +1,357 @@ +--- destructuring-group-1 --- +// This wasn't allowed. +#let ((x)) = 1 +#test(x, 1) + +--- destructuring-group-2 --- +// This also wasn't allowed. +#let ((a, b)) = (1, 2) +#test(a, 1) +#test(b, 2) + +--- destructuring-dict-underscore --- +// Here, `best` was accessed as a variable, where it shouldn't have. +#{ + (best: _) = (best: "brr") +} + +--- destructuring-dict-array-at --- +// Same here. +#{ + let array = (1, 2, 3, 4) + (test: array.at(1), best: _) = (test: "baz", best: "brr") + test(array, (1, "baz", 3, 4)) +} + +--- destructuring-dict-bad --- +// Error: 7-10 expected identifier, found group +// Error: 12-14 expected pattern, found integer +#let ((a): 10) = "world" + +--- destructuring-bad-duplicate --- +// Here, `a` is not duplicate, where it was previously identified as one. +#let f((a: b), (c,), a) = (a, b, c) +#test(f((a: 1), (2,), 3), (3, 1, 2)) + +--- destructuring-non-atomic --- +// Ensure that we can't have non-atomic destructuring. +#let x = 1 +#let c = [#() = ()] +#test(c.children.last(), [()]) + +--- destructuring-let-array --- +// Simple destructuring. +#let (a, b) = (1, 2) +#test(a, 1) +#test(b, 2) + +--- destructuring-let-array-single-item --- +#let (a,) = (1,) +#test(a, 1) + +--- destructuring-let-array-placeholders --- +// Destructuring with multiple placeholders. +#let (a, _, c, _) = (1, 2, 3, 4) +#test(a, 1) +#test(c, 3) + +--- destructuring-let-array-with-sink-at-end --- +// Destructuring with a sink. +#let (a, b, ..c) = (1, 2, 3, 4, 5, 6) +#test(a, 1) +#test(b, 2) +#test(c, (3, 4, 5, 6)) + +--- destructuring-let-array-with-sink-in-middle --- +// Destructuring with a sink in the middle. +#let (a, ..b, c) = (1, 2, 3, 4, 5, 6) +#test(a, 1) +#test(b, (2, 3, 4, 5)) +#test(c, 6) + +--- destructuring-let-array-with-sink-at-start-empty --- +// Destructuring with an empty sink. +#let (..a, b, c) = (1, 2) +#test(a, ()) +#test(b, 1) +#test(c, 2) + +--- destructuring-let-array-with-sink-in-middle-empty --- +// Destructuring with an empty sink. +#let (a, ..b, c) = (1, 2) +#test(a, 1) +#test(b, ()) +#test(c, 2) + +--- destructuring-let-array-with-sink-at-end-empty --- +// Destructuring with an empty sink. +#let (a, b, ..c) = (1, 2) +#test(a, 1) +#test(b, 2) +#test(c, ()) + +--- destructuring-let-array-with-sink-empty --- +// Destructuring with an empty sink and empty array. +#let (..a) = () +#test(a, ()) + +--- destructuring-let-array-with-unnamed-sink --- +// Destructuring with unnamed sink. +#let (a, .., b) = (1, 2, 3, 4) +#test(a, 1) +#test(b, 4) + +// Error: 10-11 duplicate binding: a +#let (a, a) = (1, 2) + +// Error: 12-15 only one destructuring sink is allowed +#let (..a, ..a) = (1, 2) + +// Error: 12-13 duplicate binding: a +#let (a, ..a) = (1, 2) + +// Error: 13-14 duplicate binding: a +#let (a: a, a) = (a: 1, b: 2) + +// Error: 13-20 expected pattern, found function call +#let (a, b: b.at(0)) = (a: 1, b: 2) + +// Error: 7-14 expected pattern, found function call +#let (a.at(0),) = (1,) + +--- destructuring-let-array-too-few-elements --- +// Error: 13-14 not enough elements to destructure +#let (a, b, c) = (1, 2) + +--- destructuring-let-array-too-few-elements-with-sink --- +// Error: 7-10 not enough elements to destructure +#let (..a, b, c, d) = (1, 2) + +--- destructuring-let-array-bool-invalid --- +// Error: 6-12 cannot destructure boolean +#let (a, b) = true + +--- destructuring-let-dict --- +// Simple destructuring. +#let (a: a, b, x: c) = (a: 1, b: 2, x: 3) +#test(a, 1) +#test(b, 2) +#test(c, 3) + +--- destructuring-let-dict-with-sink-at-end --- +// Destructuring with a sink. +#let (a: _, ..b) = (a: 1, b: 2, c: 3) +#test(b, (b: 2, c: 3)) + +--- destructuring-let-dict-with-sink-in-middle --- +// Destructuring with a sink in the middle. +#let (a: _, ..b, c: _) = (a: 1, b: 2, c: 3) +#test(b, (b: 2)) + +--- destructuring-let-dict-with-sink-at-end-empty --- +// Destructuring with an empty sink. +#let (a: _, ..b) = (a: 1) +#test(b, (:)) + +--- destructuring-let-dict-with-sink-empty --- +// Destructuring with an empty sink and empty dict. +#let (..a) = (:) +#test(a, (:)) + +--- destructuring-let-dict-with-unnamed-sink --- +// Destructuring with unnamed sink. +#let (a, ..) = (a: 1, b: 2) +#test(a, 1) + +--- destructuring-let-nested --- +// Nested destructuring. +#let ((a, b), (key: c)) = ((1, 2), (key: 3)) +#test((a, b, c), (1, 2, 3)) + +--- destructuring-let-dict-key-string-invalid --- +// Keyed destructuring is not currently supported. +// Error: 7-18 expected pattern, found string +#let ("spacy key": val) = ("spacy key": 123) +#val + +--- destructuring-let-dict-key-expr-invalid --- +// Keyed destructuring is not currently supported. +#let x = "spacy key" +// Error: 7-10 expected identifier, found group +#let ((x): v) = ("spacy key": 123) + +--- destructuring-let-array-trailing-placeholders --- +// Trailing placeholders. +// Error: 10-11 not enough elements to destructure +#let (a, _, _, _, _) = (1,) +#test(a, 1) + +--- destructuring-let-dict-patterns-invalid --- +// Error: 10-13 expected pattern, found string +// Error: 18-19 expected pattern, found integer +#let (a: "a", b: 2) = (a: 1, b: 2) + +--- destructuring-let-dict-shorthand-missing-key --- +// Error: 10-11 dictionary does not contain key "b" +#let (a, b) = (a: 1) + +--- destructuring-let-dict-missing-key --- +// Error: 10-11 dictionary does not contain key "b" +#let (a, b: b) = (a: 1) + +--- destructuring-let-dict-from-array --- +// Error: 7-11 cannot destructure named pattern from an array +#let (a: a, b) = (1, 2, 3) + +--- destructuring-during-loop-continue --- +// Test continue while destructuring. +// Should output "one = I \ two = II \ one = I". +#for num in (1, 2, 3, 1) { + let (word, roman) = if num == 1 { + ("one", "I") + } else if num == 2 { + ("two", "II") + } else { + continue + } + [#word = #roman \ ] +} + +--- destructuring-assign --- +// 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) + +--- destructuring-assign-commas --- +// Test comma placement in destructuring assignment. +#let array = (1, 2, 3) +#((key: array.at(1)) = (key: "hi")) +#test(array, (1, "hi", 3)) + +#let array = (1, 2, 3) +#((array.at(1)) = ("hi")) +#test(array, (1, "hi", 3)) + +#let array = (1, 2, 3) +#((array.at(1),) = ("hi",)) +#test(array, (1, "hi", 3)) + +#let array = (1, 2, 3) +#((array.at(1)) = ("hi",)) +#test(array, (1, ("hi",), 3)) + +--- destructuring-assign-nested --- +// Test nested destructuring assignment. +#let a +#let b +#let c +#(((a, b), (key: c)) = ((1, 2), (key: 3))) +#test((a, b, c), (1, 2, 3)) + +--- destructuring-assign-nested-invalid --- +#let array = (1, 2, 3) +// Error: 3-17 cannot destructure string +#((array.at(1),) = ("hi")) +#test(array, (1, ("hi",), 3)) + +--- issue-3275-normal-variable --- +// Normal variable. +#for x in (1, 2) {} +#for x in (a: 1, b: 2) {} +#for x in "foo" {} +#for x in bytes("😊") {} + +--- issue-3275-placeholder --- +// Placeholder. +#for _ in (1, 2) {} +#for _ in (a: 1, b: 2) {} +#for _ in "foo" {} +#for _ in bytes("😊") {} + +--- issue-3275-destructuring --- +// Destructuring. +#for (a,b,c) in (("a", 1, bytes(())), ("b", 2, bytes(""))) {} +#for (a, ..) in (("a", 1, bytes(())), ("b", 2, bytes(""))) {} +#for (k, v) in (a: 1, b: 2, c: 3) {} +#for (.., v) in (a: 1, b: 2, c: 3) {} + +--- issue-3275-loop-over-content --- +// Error: 11-17 cannot loop over content +#for x in [1, 2] {} + +--- issue-3275-loop-over-arguments --- +// Error: 11-25 cannot loop over arguments +#for _ in arguments("a") {} + +--- issue-3275-loop-over-integer --- +// Error: 16-21 cannot loop over integer +#for (x, y) in 12306 {} + +--- issue-3275-destructuring-loop-over-content --- +// Error: 16-22 cannot loop over content +#for (x, y) in [1, 2] {} + +--- issue-3275-destructuring-loop-over-string --- +// Error: 6-12 cannot destructure values of string +#for (x, y) in "foo" {} + +--- issue-3275-destructuring-loop-over-string-array --- +// Error: 6-12 cannot destructure string +#for (x, y) in ("foo", "bar") {} + +--- issue-3275-destructuring-loop-over-bytes --- +// Error: 6-12 cannot destructure values of bytes +#for (x, y) in bytes("😊") {} + +--- issue-3275-destructuring-loop-over-bytes-array --- +// Error: 6-12 cannot destructure bytes +#for (x, y) in (bytes((1,2)), bytes((1,2))) {} + +--- issue-3275-destructuring-loop-over-int-array --- +// Error: 6-12 cannot destructure integer +#for (x, y) in (1, 2) {} + +--- issue-3275-destructuring-loop-over-2d-array-1 --- +// Error: 10-11 not enough elements to destructure +#for (x, y) in ((1,), (2,)) {} + +--- issue-3275-destructuring-loop-over-2d-array-2 --- +// Error: 6-12 too many elements to destructure +#for (x, y) in ((1,2,3), (4,5,6)) {} diff --git a/tests/suite/scripting/field.typ b/tests/suite/scripting/field.typ new file mode 100644 index 00000000..7b2427e3 --- /dev/null +++ b/tests/suite/scripting/field.typ @@ -0,0 +1,76 @@ +// Test field access. + +--- field-function --- +// Test fields on function scopes. +#enum.item +#assert.eq +#assert.ne + +--- field-normal-function-invalid --- +// Error: 9-16 function `assert` does not contain field `invalid` +#assert.invalid + +--- field-elem-function-invalid --- +// Error: 7-14 function `enum` does not contain field `invalid` +#enum.invalid + +--- field-elem-function-invalid-call --- +// Error: 7-14 function `enum` does not contain field `invalid` +#enum.invalid() + +--- field-closure-invalid --- +// Closures cannot have fields. +#let f(x) = x +// Error: 4-11 cannot access fields on user-defined functions +#f.invalid + +--- field-bool-invalid --- +// Error: 8-10 cannot access fields on type boolean +#false.ok + +--- field-bool-keyword-invalid --- +// Error: 9-13 cannot access fields on type boolean +#{false.true} + +--- field-invalid-none --- +#{ + let object = none + // Error: 3-9 none does not have accessible fields + object.property = "value" +} + +--- field-invalid-int --- +#{ + let object = 10 + // Error: 3-9 integer does not have accessible fields + object.property = "value" +} + +--- field-mutable-invalid-symbol --- +#{ + let object = sym.eq.not + // Error: 3-9 cannot mutate fields on symbol + object.property = "value" +} + +--- field-mutable-invalid-module --- +#{ + let object = calc + // Error: 3-9 cannot mutate fields on module + object.property = "value" +} + +--- field-mutable-invalid-function --- +#{ + let object = calc.sin + // Error: 3-9 cannot mutate fields on function + object.property = "value" +} + +--- field-mutable-invalid-stroke --- +#{ + let s = 1pt + red + // Error: 3-4 fields on stroke are not yet mutable + // Hint: 3-4 try creating a new stroke with the updated field value instead + s.thickness = 5pt +} diff --git a/tests/suite/scripting/for.typ b/tests/suite/scripting/for.typ new file mode 100644 index 00000000..e98b3c72 --- /dev/null +++ b/tests/suite/scripting/for.typ @@ -0,0 +1,135 @@ +// Test for loops. + +--- for-loop-basic --- + +// Empty array. +#for x in () [Nope] + +// Dictionary is traversed in insertion order. +// Should output `Name: Typst. Age: 2.`. +#for (k, v) in (Name: "Typst", Age: 2) [ + #k: #v. +] + +// Block body. +// Should output `[1st, 2nd, 3rd, 4th]`. +#{ + "[" + for v in (1, 2, 3, 4) { + if v > 1 [, ] + [#v] + if v == 1 [st] + if v == 2 [nd] + if v == 3 [rd] + if v >= 4 [th] + } + "]" +} + +// Content block body. +// Should output `2345`. +#for v in (1, 2, 3, 4, 5, 6, 7) [#if v >= 2 and v <= 5 { repr(v) }] + +// Map captured arguments. +#let f1(..args) = args.pos().map(repr) +#let f2(..args) = args.named().pairs().map(p => repr(p.first()) + ": " + repr(p.last())) +#let f(..args) = (f1(..args) + f2(..args)).join(", ") +#f(1, a: 2) + +--- for-loop-integrated --- +#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").enumerate() { + test(repr(i + 1), v) +} + +// Pairs 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, ("a", 4), ("b", 5), "a", 6, "b", 7)) + +// Grapheme clusters 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" []), content) + +--- for-loop-over-bool --- +// Uniterable expression. +// Error: 11-15 cannot loop over boolean +#for v in true {} + +--- for-loop-over-string --- +// Keys and values of strings. +// Error: 6-12 cannot destructure values of string +#for (k, v) in "hi" { + dont-care +} + +--- for-loop-destructuring-without-parentheses --- +// Destructuring without parentheses. +// Error: 7-8 unexpected comma +// Hint: 7-8 destructuring patterns must be wrapped in parentheses +#for k, v in (a: 4, b: 5) { + dont-care +} + +--- for-loop-destructuring-half --- +// Error: 7-8 unexpected comma +// Hint: 7-8 destructuring patterns must be wrapped in parentheses +#for k, in () {} + +--- for-loop-incomplete --- +// Error: 5 expected pattern +#for + +// Error: 5 expected pattern +#for// + +// Error: 6 expected pattern +#{for} + +// Error: 7 expected keyword `in` +#for v + +// Error: 10 expected expression +#for v in + +// Error: 15 expected block +#for v in iter + +// Error: 5 expected pattern +#for +v in iter {} + +// Error: 7-10 expected pattern, found string +// Error: 16 expected block +A#for "v" thing + +// Error: 6-9 expected pattern, found string +#for "v" in iter {} + +// Error: 7 expected keyword `in` +#for a + b in iter {} diff --git a/tests/suite/scripting/get-rule.typ b/tests/suite/scripting/get-rule.typ new file mode 100644 index 00000000..24d4e5db --- /dev/null +++ b/tests/suite/scripting/get-rule.typ @@ -0,0 +1,67 @@ +--- get-rule-basic --- +// Test basic get rule. +#context test(text.lang, "en") +#set text(lang: "de") +#context test(text.lang, "de") +#text(lang: "es", context test(text.lang, "es")) + +--- get-rule-in-function --- +// Test whether context is retained in nested function. +#let translate(..args) = args.named().at(text.lang) +#set text(lang: "de") +#context test(translate(de: "Inhalt", en: "Contents"), "Inhalt") + +--- get-rule-in-array-callback --- +// Test whether context is retained in built-in callback. +#set text(lang: "de") +#context test( + ("en", "de", "fr").sorted(key: v => v != text.lang), + ("de", "en", "fr"), +) + +--- get-rule-folding --- +// Test folding. +#set rect(stroke: red) +#context { + test(type(rect.stroke), stroke) + test(rect.stroke.paint, red) +} +#[ + #set rect(stroke: 4pt) + #context test(rect.stroke, 4pt + red) +] +#context test(rect.stroke, stroke(red)) + +--- get-rule-figure-caption-collision --- +// We have one collision: `figure.caption` could be both the element and a get +// rule for the `caption` field, which is settable. We always prefer the +// element. It's unfortunate, but probably nobody writes +// `set figure(caption: ..)` anyway. +#test(type(figure.caption), function) +#context test(type(figure.caption), function) + +--- get-rule-assertion-failure --- +// Error: 10-31 Assertion failed: "en" != "de" +#context test(text.lang, "de") + +--- get-rule-unknown-field --- +// Error: 15-20 function `text` does not contain field `langs` +#context text.langs + +--- get-rule-inherent-field --- +// Error: 18-22 function `heading` does not contain field `body` +#context heading.body + +--- get-rule-missing-context-no-context --- +// Error: 7-11 can only be used when context is known +// Hint: 7-11 try wrapping this in a `context` expression +// Hint: 7-11 the `context` expression should wrap everything that depends on this function +#text.lang + +--- get-rule-unknown-field-no-context --- +// Error: 7-12 function `text` does not contain field `langs` +#text.langs + +--- get-rule-inherent-field-no-context --- +// Error: 10-14 function `heading` does not contain field `body` +#heading.body diff --git a/tests/suite/scripting/if.typ b/tests/suite/scripting/if.typ new file mode 100644 index 00000000..cc88925f --- /dev/null +++ b/tests/suite/scripting/if.typ @@ -0,0 +1,134 @@ +// Test if-else expressions. + +--- if-markup --- +// Test condition evaluation. +#if 1 < 2 [ + One. +] + +#if true == false [ + {Bad}, but we {dont-care}! +] + +--- if-condition-complex --- +// Braced condition. +#if {true} [ + One. +] + +// Content block in condition. +#if [] != none [ + Two. +] + +// Multi-line condition with parens. +#if ( + 1 + 1 + == 1 +) [ + Nope. +] else { + "Three." +} + +// Multiline. +#if false [ + Bad. +] else { + let point = "." + "Four" + point +} + +// Content block can be argument or body depending on whitespace. +#{ + if content == type[b] [Fi] else [Nope] + if content == type [Nope] else [ve.] +} + +#let i = 3 +#if i < 2 [ + Five. +] else if i < 4 [ + Six. +] else [ + Seven. +] + +--- if-else-if-else --- +// Test else if. + +#let nth(n) = { + str(n) + if n == 1 { "st" } + else if n == 2 { "nd" } + else if n == 3 { "rd" } + else { "th" } +} + +#test(nth(1), "1st") +#test(nth(2), "2nd") +#test(nth(3), "3rd") +#test(nth(4), "4th") +#test(nth(5), "5th") + +--- if-expression --- +// Value of if expressions. + +#{ + let x = 1 + let y = 2 + let z + + // Returns if branch. + z = if x < y { "ok" } + test(z, "ok") + + // Returns else branch. + z = if x > y { "bad" } else { "ok" } + test(z, "ok") + + // Missing else evaluates to none. + z = if x > y { "bad" } + test(z, none) +} + +--- if-condition-string-invalid --- +// 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 } + +--- if-condition-invalid-and-wrong-type --- +// Make sure that we don't complain twice. +// Error: 5-12 cannot add integer and string +#if 1 + "2" {} + +--- if-incomplete --- +// Error: 4 expected expression +#if + +// Error: 5 expected expression +#{if} + +// Error: 6 expected block +#if x + +// Error: 2-6 unexpected keyword `else` +#else {} + +// Should output `x`. +// Error: 4 expected expression +#if +x {} + +// Should output `something`. +// Error: 6 expected block +#if x something + +// Should output `A thing.` +// Error: 19 expected block +A#if false {} else thing + +#if a []else [b] +#if a [] else [b] +#if a {} else [b] diff --git a/tests/suite/scripting/import.typ b/tests/suite/scripting/import.typ new file mode 100644 index 00000000..820f81d6 --- /dev/null +++ b/tests/suite/scripting/import.typ @@ -0,0 +1,334 @@ +// Test function and module imports. + +--- import-basic --- +// Test basic syntax and semantics. + +// Test that this will be overwritten. +#let value = [foo] + +// Import multiple things. +#import "module.typ": fn, value +#fn[Like and Subscribe!] +#value + +// Should output `bye`. +// Stop at semicolon. +#import "module.typ": a, c;bye + +--- import-item-markup --- +// An item import. +#import "module.typ": item +#test(item(1, 2), 3) + +--- import-item-in-code --- +// Code mode +#{ + import "module.typ": b + test(b, 1) +} + +--- import-wildcard-in-markup --- +// A wildcard import. +#import "module.typ": * + +// It exists now! +#test(d, 3) + +--- import-item-renamed --- +// A renamed item import. +#import "module.typ": item as something +#test(something(1, 2), 3) + +--- import-items-renamed-mixed --- +// Mixing renamed and not renamed items. +#import "module.typ": fn, b as val, item as other +#test(val, 1) +#test(other(1, 2), 3) + +--- import-from-function-scope --- +// Test importing from function scopes. + +#import enum: item +#import assert.with(true): * + +#enum( + item(1)[First], + item(5)[Fifth] +) +#eq(10, 10) +#ne(5, 6) + +--- import-from-function-scope-item-renamed --- +// Test renaming items imported from function scopes. +#import assert: eq as aseq +#aseq(10, 10) + +--- import-from-file-bare --- +// A module import without items. +#import "module.typ" +#test(module.b, 1) +#test(module.item(1, 2), 3) +#test(module.push(2), 3) + +--- import-from-file-renamed --- +// A renamed module import without items. +#import "module.typ" as other +#test(other.b, 1) +#test(other.item(1, 2), 3) +#test(other.push(2), 3) + +--- import-from-file-items-renamed-mixed --- +// Mixing renamed module and items. +#import "module.typ" as newname: b as newval, item +#test(newname.b, 1) +#test(newval, 1) +#test(item(1, 2), 3) +#test(newname.item(1, 2), 3) + +--- import-from-function-scope-renamed --- +// Renamed module import with function scopes. +#import enum as othernum +#test(enum, othernum) + +--- import-from-function-scope-renamed-twice --- +// Mixing renamed module import from function with renamed item import. +#import assert as asrt +#import asrt: ne as asne +#asne(1, 2) + +--- import-module-item-name-mutating --- +// Edge case for module access that isn't fixed. +#import "module.typ" + +// Works because the method name isn't categorized as mutating. +#test((module,).at(0).item(1, 2), 3) + +// Doesn't work because of mutating name. +// Error: 2-11 cannot mutate a temporary value +#(module,).at(0).push() + +--- import-no-whitespace --- +// Who needs whitespace anyways? +#import"module.typ":* + +--- import-trailing-comma --- +// Allow the trailing comma. +#import "module.typ": a, c, + +--- import-source-field-access --- +// Usual importing syntax also works for function scopes +#let d = (e: enum) +#import d.e +#import d.e as renamed +#import d.e: item +#item(2)[a] + +--- import-item-rename-unnecessary --- +// Warning: 23-27 unnecessary import rename to same name +#import enum: item as item + +--- import-rename-unnecessary --- +// Warning: 17-21 unnecessary import rename to same name +#import enum as enum + +--- import-rename-unnecessary-mixed --- +// Warning: 17-21 unnecessary import rename to same name +#import enum as enum: item + +// Warning: 17-21 unnecessary import rename to same name +// Warning: 31-35 unnecessary import rename to same name +#import enum as enum: item as item + +--- import-item-rename-unnecessary-but-ok --- +// No warning on a case that isn't obviously pathological +#import "module.typ" as module + +--- import-from-closure-invalid --- +// Can't import from closures. +#let f(x) = x +// Error: 9-10 cannot import from user-defined functions +#import f: x + +--- import-from-closure-renamed-invalid --- +// Can't import from closures, despite renaming. +#let f(x) = x +// Error: 9-10 cannot import from user-defined functions +#import f as g + +--- import-from-with-closure-invalid --- +// Can't import from closures, despite modifiers. +#let f(x) = x +// Error: 9-18 cannot import from user-defined functions +#import f.with(5): x + +--- import-from-with-closure-literal-invalid --- +// Error: 9-18 cannot import from user-defined functions +#import () => {5}: x + +--- import-from-int-invalid --- +// Error: 9-10 expected path, module, function, or type, found integer +#import 5: something + +--- import-from-int-renamed-invalid --- +// Error: 9-10 expected path, module, function, or type, found integer +#import 5 as x + +--- import-from-string-invalid --- +// Error: 9-11 failed to load file (is a directory) +#import "": name + +--- import-from-string-renamed-invalid --- +// Error: 9-11 failed to load file (is a directory) +#import "" as x + +--- import-file-not-found-invalid --- +// Error: 9-20 file not found (searched at tests/suite/scripting/lib/0.2.1) +#import "lib/0.2.1" + +--- import-file-not-found-renamed-invalid --- +// Error: 9-20 file not found (searched at tests/suite/scripting/lib/0.2.1) +#import "lib/0.2.1" as x + +--- import-file-not-valid-utf-8 --- +// Some non-text stuff. +// Error: 9-35 file is not valid utf-8 +#import "/assets/images/rhino.png" + +--- import-item-not-found --- +// Unresolved import. +// Error: 23-35 unresolved import +#import "module.typ": non_existing + +--- import-cyclic --- +// Cyclic import of this very file. +// Error: 9-23 cyclic import +#import "./import.typ" + +--- import-cyclic-in-other-file --- +// Cyclic import in other file. +#import "./modules/cycle1.typ": * + +This is never reached. + +--- import-renamed-old-name --- +// Renaming does not import the old name (without items). +#import "./modules/chap1.typ" as something +#test(something.name, "Klaus") +// Error: 7-12 unknown variable: chap1 +#test(chap1.name, "Klaus") + +--- import-items-renamed-old-name --- +// Renaming does not import the old name (with items). +#import "./modules/chap1.typ" as something: name as other +#test(other, "Klaus") +#test(something.name, "Klaus") +// Error: 7-12 unknown variable: chap1 +#test(chap1.b, "Klaus") + +--- import-incomplete --- +// Error: 8 expected expression +#import + +--- import-item-string-invalid --- +// Error: 26-29 unexpected string +#import "module.typ": a, "b", c + +--- import-bad-token --- +// Error: 23-24 unexpected equals sign +#import "module.typ": = + +--- import-duplicate-comma --- +// An additional trailing comma. +// Error: 31-32 unexpected comma +#import "module.typ": a, b, c,, + +--- import-no-colon --- +// Error: 2:2 expected semicolon or line break +#import "module.typ +"stuff + +--- import-bad-token-star --- +// A star in the list. +// Error: 26-27 unexpected star +#import "module.typ": a, *, b + +--- import-item-after-star --- +// An item after a star. +// Error: 24 expected semicolon or line break +#import "module.typ": *, a + +--- import-bad-colon-in-items --- +// Error: 14-15 unexpected colon +// Error: 16-17 unexpected integer +#import "": a: 1 + +--- import-missing-comma --- +// Error: 14 expected comma +#import "": a b + +--- import-from-package-bare --- +// Test import without items. +#import "@test/adder:0.1.0" +#test(adder.add(2, 8), 10) + +--- import-from-package-items --- +// Test import with items. +#import "@test/adder:0.1.0": add +#test(add(2, 8), 10) + +--- import-from-package-required-compiler-version --- +// Test too high required compiler version. +// Error: 9-29 package requires typst 1.0.0 or newer (current version is VERSION) +#import "@test/future:0.1.0": future + +--- import-from-package-namespace-invalid-1 --- +// Error: 9-13 `@` is not a valid package namespace +#import "@@": * + +--- import-from-package-name-missing-1 --- +// Error: 9-16 package specification is missing name +#import "@heya": * + +--- import-from-package-namespace-invalid-2 --- +// Error: 9-15 `123` is not a valid package namespace +#import "@123": * + +--- import-from-package-name-missing-2 --- +// Error: 9-17 package specification is missing name +#import "@test/": * + +--- import-from-package-version-missing-1 --- +// Error: 9-22 package specification is missing version +#import "@test/mypkg": * + +--- import-from-package-name-invalid --- +// Error: 9-20 `$$$` is not a valid package name +#import "@test/$$$": * + +--- import-from-package-version-missing-2 --- +// Error: 9-23 package specification is missing version +#import "@test/mypkg:": * + +--- import-from-package-version-missing-minor --- +// Error: 9-24 version number is missing minor version +#import "@test/mypkg:0": * + +--- import-from-package-version-major-invalid-1 --- +// Error: 9-29 `latest` is not a valid major version +#import "@test/mypkg:latest": * + +--- import-from-package-version-major-invalid-2 --- +// Error: 9-29 `-3` is not a valid major version +#import "@test/mypkg:-3.0.0": * + +--- import-from-package-version-missing-patch-1 --- +// Error: 9-26 version number is missing patch version +#import "@test/mypkg:0.3": * + +--- import-from-package-version-missing-patch-2 --- +// Error: 9-27 version number is missing patch version +#import "@test/mypkg:0.3.": * + +--- import-from-file-package-lookalike --- +// Error: 9-28 file not found (searched at tests/suite/scripting/#test/mypkg:1.0.0) +#import "#test/mypkg:1.0.0": * diff --git a/tests/suite/scripting/include.typ b/tests/suite/scripting/include.typ new file mode 100644 index 00000000..e4da6d19 --- /dev/null +++ b/tests/suite/scripting/include.typ @@ -0,0 +1,32 @@ +// Test module includes. + +--- include-file --- +#set page(width: 200pt) + += Document + +// Include a file +#include "modules/chap1.typ" + +// Expression as a file name. +#let chap2 = include "modu" + "les/chap" + "2.typ" + +-- _Intermission_ -- +#chap2 + +--- include-file-not-found --- +#{ + // Error: 19-38 file not found (searched at tests/suite/scripting/modules/chap3.typ) + let x = include "modules/chap3.typ" +} + +--- include-no-bindings --- +#include "modules/chap1.typ" + +// The variables of the file should not appear in this scope. +// Error: 2-6 unknown variable: name +#name + +--- include-semicolon-or-linebreak --- +// Error: 18 expected semicolon or line break +#include "hi.typ" Hi diff --git a/tests/suite/scripting/let.typ b/tests/suite/scripting/let.typ new file mode 100644 index 00000000..2604c4ea --- /dev/null +++ b/tests/suite/scripting/let.typ @@ -0,0 +1,143 @@ +// Test let bindings. + +--- let-basic --- +// Automatically initialized with none. +#let x +#test(x, none) + +// Manually initialized with one. +#let z = 1 +#test(z, 1) + +// Syntax sugar for function definitions. +#let fill = conifer +#let f(body) = rect(width: 2cm, fill: fill, inset: 5pt, body) +#f[Hi!] + +--- let-termination --- +// Termination. + +// Terminated by line break. +#let v1 = 1 +One + +// Terminated by semicolon. +#let v2 = 2; Two + +// Terminated by semicolon and line break. +#let v3 = 3; +Three + +#test(v1, 1) +#test(v2, 2) +#test(v3, 3) + +--- let-valid-idents --- +// Test what constitutes a valid Typst identifier. +#let name = 1 +#test(name, 1) +#let name_ = 1 +#test(name_, 1) +#let name-2 = 1 +#test(name-2, 1) +#let name_2 = 1 +#test(name_2, 1) +#let __name = 1 +#test(__name, 1) +#let ůñıćóðė = 1 +#test(ůñıćóðė, 1) + +--- let-binding-keyword-in-markup --- +// Error: 6-8 expected pattern, found keyword `as` +// Hint: 6-8 keyword `as` is not allowed as an identifier; try `as_` instead +#let as = 1 + 2 + +--- let-binding-keyword-in-code --- +#{ + // Error: 7-9 expected pattern, found keyword `as` + // Hint: 7-9 keyword `as` is not allowed as an identifier; try `as_` instead + let as = 10 +} + +--- let-ident-parenthesized --- +// Test parenthesised assignments. +#let (a) = (1, 2) + +--- let-incomplete --- +// Error: 5 expected pattern +#let + +// Error: 6 expected pattern +#{let} + +// Error: 6-9 expected pattern, found string +#let "v" + +// Error: 7 expected semicolon or line break +#let v 1 + +// Error: 9 expected expression +#let v = + +// Error: 6-9 expected pattern, 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: 18 expected expression +// Error: 11-12 unclosed delimiter +#let v5 = (1, 2 + ; Five + +// Error: 9-13 expected pattern, found boolean +#let (..true) = false + +--- underscore-invalid --- +#let _ = 4 + +#for _ in range(2) [] + +// Error: 2-3 unexpected underscore +#_ + +// Error: 8-9 expected expression, found underscore +#lorem(_) + +// Error: 3-4 expected expression, found underscore +#(_,) + +// Error: 3-4 expected expression, found underscore +#{_} + +// Error: 8-9 expected expression, found underscore +#{ 1 + _ } + +--- let-function-incomplete --- +// Error: 13 expected equals sign +#let func(x) + +// Error: 15 expected expression +#let func(x) = + +--- let-function-parenthesized --- +// This is not yet parsed in the ideal way. +// Error: 12 expected equals sign +#let (func)(x) + +--- let-function-parenthesized-with-init --- +// These errors aren't great. +// Error: 12 expected equals sign +// Error: 15-15 expected semicolon or line break +#let (func)(x) = 3 + +--- let-with-no-init-group --- +// This was unintentionally allowed ... +// Error: 9 expected equals sign +#let (a) + +--- let-with-no-init-destructuring --- +// ... where this wasn't. +// Error: 12 expected equals sign +#let (a, b) diff --git a/tests/suite/scripting/loop.typ b/tests/suite/scripting/loop.typ new file mode 100644 index 00000000..689c1c93 --- /dev/null +++ b/tests/suite/scripting/loop.typ @@ -0,0 +1,142 @@ +// Test break and continue in loops. + +--- loop-break-basic --- +// Test break. + +#let var = 0 +#let error = false + +#for i in range(10) { + var += i + if i > 5 { + break + error = true + } +} + +#test(var, 21) +#test(error, false) + +--- loop-break-join-basic --- +// Test joining with break. + +#let i = 0 +#let x = while true { + i += 1 + str(i) + if i >= 5 { + "." + break + } +} + +#test(x, "12345.") + +--- loop-continue-basic --- +// Test continue. + +#let i = 0 +#let x = 0 + +#while x < 8 { + i += 1 + if calc.rem(i, 3) == 0 { + continue + } + x += i +} + +// If continue did not work, this would equal 10. +#test(x, 12) + +--- loop-continue-join --- +// Test joining with continue. + +#let x = for i in range(5) { + "a" + if calc.rem(i, 3) == 0 { + "_" + continue + } + str(i) +} + +#test(x, "a_a1a2a_a4") + +--- loop-break-outside-of-loop --- +// Test break outside of loop. +#let f() = { + // Error: 3-8 cannot break outside of loop + break +} + +#for i in range(1) { + f() +} + +--- loop-break-join-in-last-arg --- +// Test break in function call. +#let identity(x) = x +#let out = for i in range(5) { + "A" + identity({ + "B" + break + }) + "C" +} + +#test(out, "AB") + +--- loop-continue-outside-of-loop-in-block --- +// Test continue outside of loop. + +// Error: 12-20 cannot continue outside of loop +#let x = { continue } + +--- loop-continue-outside-of-loop-in-markup --- +// Error: 2-10 cannot continue outside of loop +#continue + +--- loop-break-join-in-nested-blocks --- +// Should output `Hello World 🌎`. +#for _ in range(10) { + [Hello ] + [World #{ + [🌎] + break + }] +} + +--- loop-break-join-set-and-show --- +// Should output `Some` in red, `Some` in blue and `Last` in green. +// Everything should be in smallcaps. +#for color in (red, blue, green, yellow) [ + #set text(font: "Roboto") + #show: it => text(fill: color, it) + #smallcaps(if color != green [ + Some + ] else [ + Last + #break + ]) +] + +--- loop-break-join-in-set-rule-args --- +// Test break in set rule. +// Should output `Hi` in blue. +#for i in range(10) { + [Hello] + set text(blue, ..break) + [Not happening] +} + +--- loop-break-join-in-first-arg --- +// Test second block during break flow. + +#for i in range(10) { + table( + { [A]; break }, + for _ in range(3) [B] + ) +} diff --git a/tests/suite/scripting/methods.typ b/tests/suite/scripting/methods.typ new file mode 100644 index 00000000..5deea2cf --- /dev/null +++ b/tests/suite/scripting/methods.typ @@ -0,0 +1,51 @@ +// Test method calls. + +--- method-whitespace --- +// Test whitespace around dot. +#test( "Hi there" . split() , ("Hi", "there")) + +--- method-mutating --- +// Test mutating indexed value. +#{ + let matrix = (((1,), (2,)), ((3,), (4,))) + matrix.at(1).at(0).push(5) + test(matrix, (((1,), (2,)), ((3, 5), (4,)))) +} + +--- method-multiline --- +// Test multiline chain in code block. +#{ + let rewritten = "Hello. This is a sentence. And one more." + .split(".") + .map(s => s.trim()) + .filter(s => s != "") + .map(s => s + "!") + .join("\n ") + + test(rewritten, "Hello!\n This is a sentence!\n And one more!") +} + +--- method-unknown --- +// Error: 2:10-2:13 type array has no method `fun` +#let numbers = () +#numbers.fun() + +--- method-unknown-but-field-exists --- +// Error: 2:4-2:10 type content has no method `stroke` +// Hint: 2:4-2:10 did you mean to access the field `stroke`? +#let l = line(stroke: red) +#l.stroke() + +--- method-mutate-on-temporary --- +// Error: 2:2-2:43 cannot mutate a temporary value +#let numbers = (1, 2, 3) +#numbers.map(v => v / 2).sorted().map(str).remove(4) + +--- assign-to-method-invalid --- +// Error: 2:3-2:19 cannot mutate a temporary value +#let numbers = (1, 2, 3) +#(numbers.sorted() = 1) + +--- method-mutate-on-std-constant --- +// Error: 2-5 cannot mutate a constant: box +#box.push(1) diff --git a/tests/suite/scripting/module.typ b/tests/suite/scripting/module.typ new file mode 100644 index 00000000..8a67d225 --- /dev/null +++ b/tests/suite/scripting/module.typ @@ -0,0 +1,13 @@ +// SKIP +// A file to import in import / include tests. + +#let a +#let b = 1 +#let c = 2 +#let d = 3 +#let value = [hi] +#let item(a, b) = a + b +#let push(a) = a + 1 +#let fn = rect.with(fill: conifer, inset: 5pt) + +Some _includable_ text. diff --git a/tests/suite/scripting/modules/chap1.typ b/tests/suite/scripting/modules/chap1.typ new file mode 100644 index 00000000..13d0acf8 --- /dev/null +++ b/tests/suite/scripting/modules/chap1.typ @@ -0,0 +1,8 @@ +// SKIP +#let name = "Klaus" + +== Chapter 1 +#name stood in a field of wheat. There was nothing of particular interest about +the field #name just casually surveyed for any paths on which the corn would not +totally ruin his semi-new outdorsy jacket but then again, most of us spend +considerable time in non-descript environments. diff --git a/tests/suite/scripting/modules/chap2.typ b/tests/suite/scripting/modules/chap2.typ new file mode 100644 index 00000000..9c9d12d7 --- /dev/null +++ b/tests/suite/scripting/modules/chap2.typ @@ -0,0 +1,10 @@ +// SKIP +#let name = "Klaus" + +== Chapter 2 +Their motivations, however, were pretty descript, so to speak. #name had not yet +conceptualized their consequences, but that should change pretty quickly. #name +approached the center of the field and picked up a 4-foot long disk made from +what could only be cow manure. The hair on the back of #name' neck bristled as +he stared at the unusual sight. After studying the object for a while, he +promptly popped the question, "How much?" diff --git a/tests/suite/scripting/modules/cycle1.typ b/tests/suite/scripting/modules/cycle1.typ new file mode 100644 index 00000000..0f924ac7 --- /dev/null +++ b/tests/suite/scripting/modules/cycle1.typ @@ -0,0 +1,5 @@ +// SKIP +#import "cycle2.typ": * +#let inaccessible = "wow" + +This is the first element of an import cycle. diff --git a/tests/suite/scripting/modules/cycle2.typ b/tests/suite/scripting/modules/cycle2.typ new file mode 100644 index 00000000..69eb2033 --- /dev/null +++ b/tests/suite/scripting/modules/cycle2.typ @@ -0,0 +1,5 @@ +// SKIP +#import "cycle1.typ": * +#let val = "much cycle" + +This is the second element of an import cycle. diff --git a/tests/suite/scripting/ops.typ b/tests/suite/scripting/ops.typ new file mode 100644 index 00000000..0f13d212 --- /dev/null +++ b/tests/suite/scripting/ops.typ @@ -0,0 +1,465 @@ +// Test binary expressions. + +--- ops-add-content --- +// Test adding content. +#([*Hello* ] + [world!]) + +--- ops-unary-basic --- +// 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)) + +--- ops-add-too-large --- +// Error: 3-26 value is too large +#(9223372036854775807 + 1) + +--- ops-binary-basic --- +// 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) + } +} + +--- ops-multiply-inf-with-length --- +// Test that multiplying infinite numbers by certain units does not crash. +#(float("inf") * 1pt) +#(float("inf") * 1em) +#(float("inf") * (1pt + 1em)) + +--- ops-attempt-nan-length --- +// 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) + +--- ops-unary-bool --- +// 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) + +--- ops-equality --- +// 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) + +--- ops-compare --- +// 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((0, 1, 2, 4) < (0, 1, 2, 5), true) +#test((0, 1, 2, 4) < (0, 1, 2, 3), false) +#test((0, 1, 2, 3.3) > (0, 1, 2, 4), false) +#test((0, 1, 2) < (0, 1, 2, 3), true) +#test((0, 1, "b") > (0, 1, "a", 3), true) +#test((0, 1.1, 3) >= (0, 1.1, 3), true) +#test((0, 1, datetime(day: 1, month: 12, year: 2023)) <= (0, 1, datetime(day: 1, month: 12, year: 2023), 3), true) +#test(("a", 23, 40, "b") > ("a", 23, 40), true) +#test(() <= (), true) +#test(() >= (), true) +#test(() <= (1,), true) +#test((1,) <= (), false) + +--- ops-in --- +// 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) + +--- ops-not-trailing --- +// Error: 10 expected keyword `in` +#("a" not) + +--- func-with --- +// Test `with` method. + +// Apply positional arguments. +#let add(x, y) = x + y +#test(add.with(2)(3), 5) +#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) + +// Apply arguments to an argument sink. +#let times(..sink) = { + let res = sink.pos().product() + if sink.named().at("negate", default: false) { res *= -1 } + res +} +#test((times.with(2, negate: true).with(5))(), -10) +#test((times.with(2).with(5).with(negate: true))(), -10) +#test((times.with(2).with(5, negate: true))(), -10) +#test((times.with(2).with(negate: true))(5), -10) + +--- ops-precedence-basic --- +// Multiplication binds stronger than addition. +#test(1+2*-3, -5) + +// Subtraction binds stronger than comparison. +#test(3 == 5 - 2, true) + +// Boolean operations bind stronger than '=='. +#test("a" == "a" and 2 < 3, true) +#test(not "b" == "b", false) + +--- ops-precedence-boolean-ops --- +// Assignment binds stronger than boolean operations. +// Error: 2:3-2:8 cannot mutate a temporary value +#let x = false +#(not x = "a") + +--- ops-precedence-unary --- +// Precedence doesn't matter for chained unary operators. +// Error: 3-12 cannot apply '-' to boolean +#(-not true) + +--- ops-precedence-not-in --- +// Not in handles precedence. +#test(-1 not in (1, 2, 3), true) + +--- ops-precedence-parentheses --- +// Parentheses override precedence. +#test((1), 1) +#test((1+2)*-3, -9) + +// Error: 8-9 unclosed delimiter +#test({(1 + 1}, 2) + +--- ops-associativity-left --- +// Math operators are left-associative. +#test(10 / 2 / 2 == (10 / 2) / 2, true) +#test(10 / 2 / 2 == 10 / (2 / 2), false) +#test(1 / 2 * 3, 1.5) + +--- ops-associativity-right --- +// Assignment is right-associative. +#{ + let x = 1 + let y = 2 + x = y = "ok" + test(x, none) + test(y, "ok") +} + +--- ops-unary-minus-missing-expr --- +// Error: 4 expected expression +#(-) + +--- ops-add-missing-rhs --- +// Error: 10 expected expression +#test({1+}, 1) + +--- ops-mul-missing-rhs --- +// Error: 10 expected expression +#test({2*}, 2) + +--- ops-unary-plus-on-content --- +// Error: 3-13 cannot apply unary '+' to content +#(+([] + [])) + +--- ops-unary-plus-on-string --- +// Error: 3-6 cannot apply '-' to string +#(-"") + +--- ops-not-on-array --- +// Error: 3-9 cannot apply 'not' to array +#(not ()) + +--- ops-compare-relative-length-and-ratio --- +// Error: 3-19 cannot compare relative length and ratio +#(30% + 1pt <= 40%) + +--- ops-compare-em-with-abs --- +// Error: 3-14 cannot compare 1em with 10pt +#(1em <= 10pt) + +--- ops-compare-normal-float-with-nan --- +// Error: 3-22 cannot compare 2.2 with NaN +#(2.2 <= float("nan")) + +--- ops-compare-int-and-str --- +// Error: 3-26 cannot compare integer and string +#((0, 1, 3) > (0, 1, "a")) + +--- ops-compare-array-nested-failure --- +// Error: 3-42 cannot compare 3.5 with NaN +#((0, "a", 3.5) <= (0, "a", float("nan"))) + +--- ops-divide-by-zero-float --- +// Error: 3-12 cannot divide by zero +#(1.2 / 0.0) + +--- ops-divide-by-zero-int --- +// Error: 3-8 cannot divide by zero +#(1 / 0) + +--- ops-divide-by-zero-angle --- +// Error: 3-15 cannot divide by zero +#(15deg / 0deg) + +--- ops-binary-arithmetic-error-message --- +// Special messages for +, -, * and /. +// Error: 3-10 cannot add integer and string +#(1 + "2", 40% - 1) + +--- add-assign-int-and-str --- +// Error: 15-23 cannot add integer and string +#{ let x = 1; x += "2" } + +--- ops-divide-ratio-by-length --- +// Error: 4-13 cannot divide ratio by length +#( 10% / 5pt ) + +--- ops-divide-em-by-abs --- +// Error: 3-12 cannot divide these two lengths +#(1em / 5pt) + +--- ops-divide-relative-length-by-ratio --- +// Error: 3-19 cannot divide relative length by ratio +#((10% + 1pt) / 5%) + +--- ops-divide-relative-lengths --- +// Error: 3-28 cannot divide these two relative lengths +#((10% + 1pt) / (20% + 1pt)) + +--- ops-subtract-int-from-ratio --- +// Error: 13-20 cannot subtract integer from ratio +#((1234567, 40% - 1)) + +--- ops-multiply-int-with-bool --- +// Error: 3-11 cannot multiply integer with boolean +#(2 * true) + +--- ops-divide-int-by-length --- +// Error: 3-11 cannot divide integer by length +#(3 / 12pt) + +--- multiply-negative-int-with-str --- +// Error: 3-10 number must be at least zero +#(-1 * "") + +--- ops-assign --- +// 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") + +--- ops-assign-unknown-var-lhs --- +#{ + // Error: 3-6 unknown variable: a-1 + // Hint: 3-6 if you meant to use subtraction, try adding spaces around the minus sign + a-1 = 2 +} + +--- ops-assign-unknown-var-rhs --- +#{ + let a = 2 + a = 1-a + a = a -1 + + // Error: 7-10 unknown variable: a-1 + // Hint: 7-10 if you meant to use subtraction, try adding spaces around the minus sign + a = a-1 +} + +--- ops-assign-unknown-parenthesized-variable --- +// Error: 4-5 unknown variable: x +#((x) = "") + +--- ops-assign-destructuring-unknown-variable --- +// Error: 4-5 unknown variable: x +#((x,) = (1,)) + +--- ops-assign-to-temporary --- +// Error: 3-8 cannot mutate a temporary value +#(1 + 2 += 3) + +--- ops-assign-to-invalid-unary-op --- +// Error: 2:3-2:8 cannot apply 'not' to string +#let x = "Hey" +#(not x = "a") + +--- ops-assign-to-invalid-binary-op --- +// Error: 7-8 unknown variable: x +#(1 + x += 3) + +--- ops-assign-unknown-variable --- +// Error: 3-4 unknown variable: z +#(z = 1) + +--- ops-assign-to-std-constant --- +// Error: 3-7 cannot mutate a constant: rect +#(rect = "hi") + +--- ops-assign-to-shadowed-std-constant --- +// Works if we define rect beforehand +// (since then it doesn't resolve to the standard library version anymore). +#let rect = "" +#(rect = "hi") diff --git a/tests/suite/scripting/params.typ b/tests/suite/scripting/params.typ new file mode 100644 index 00000000..688124f2 --- /dev/null +++ b/tests/suite/scripting/params.typ @@ -0,0 +1,69 @@ +--- param-underscore-missing-argument --- +// Error: 17-20 missing argument: pattern parameter +#let f(a: 10) = a() + 1 +#f(a: _ => 5) + +--- params-sink-named --- +// ... but this was. +#let f(..x) = {} +#f(arg: 1) + +--- params-sink-unnamed --- +// unnamed spread +#let f(.., a) = a +#test(f(1, 2, 3), 3) + +// This wasn't allowed before the bug fix ... +#let f(..) = 2 +#test(f(arg: 1), 2) + +--- params-sink-bool-invalid --- +// Error: 10-14 expected pattern, found boolean +#let f(..true) = none + +--- params-sink-multiple-invalid --- +// Error: 13-16 only one argument sink is allowed +#let f(..a, ..b) = none + +--- params-sink-at-start --- +// Spread at beginning. +#{ + let f(..a, b) = (a, b) + test(repr(f(1)), "((), 1)") + test(repr(f(1, 2, 3)), "((1, 2), 3)") + test(repr(f(1, 2, 3, 4, 5)), "((1, 2, 3, 4), 5)") +} + +--- params-sink-in-middle --- +// Spread in the middle. +#{ + let f(a, ..b, c) = (a, b, c) + test(repr(f(1, 2)), "(1, (), 2)") + test(repr(f(1, 2, 3, 4, 5)), "(1, (2, 3, 4), 5)") +} + +--- params-sink-unnamed-empty --- +// Unnamed sink should just ignore any extra arguments. +#{ + let f(a, b: 5, ..) = (a, b) + test(f(4), (4, 5)) + test(f(10, b: 11), (10, 11)) + test(f(13, 20, b: 12), (13, 12)) + test(f(15, b: 16, c: 13), (15, 16)) +} + +--- params-sink-missing-arguments --- +#{ + let f(..a, b, c, d) = none + + // Error: 3-10 missing argument: d + f(1, 2) +} + +--- issue-1029-parameter-destructuring --- +// Test that underscore works in parameter patterns. +#test((1, 2, 3).zip((1, 2, 3)).map(((_, x)) => x), (1, 2, 3)) + +--- issue-1351-parameter-dictionary --- +// Error: 17-22 expected pattern, found string +#let foo((test: "bar")) = {} diff --git a/tests/suite/scripting/recursion.typ b/tests/suite/scripting/recursion.typ new file mode 100644 index 00000000..43fe848e --- /dev/null +++ b/tests/suite/scripting/recursion.typ @@ -0,0 +1,55 @@ +// Test recursive function calls. + +--- recursion-named --- +// Test with named function. +#let fib(n) = { + if n <= 2 { + 1 + } else { + fib(n - 1) + fib(n - 2) + } +} + +#test(fib(10), 55) + +--- recursion-unnamed-invalid --- +// Test with unnamed function. +// Error: 17-18 unknown variable: f +#let f = (n) => f(n - 1) +#f(10) + +--- recursion-named-returns-itself --- +// Test capturing with named function. +#let f = 10 +#let f() = f +#test(type(f()), function) + +--- recursion-unnamed-does-not-return-itself --- +// Test capturing with unnamed function. +#let f = 10 +#let f = () => f +#test(type(f()), int) + +--- recursion-shadowing --- +// Test redefinition. +#let f(x) = "hello" +#let f(x) = if x != none { f(none) } else { "world" } +#test(f(1), "world") + +--- recursion-maximum-depth --- +// Error: 15-21 maximum function call depth exceeded +#let rec(n) = rec(n) + 1 +#rec(1) + +--- recursion-via-include-in-layout --- +// Test cyclic imports during layout. +// Error: 2-38 maximum show rule depth exceeded +// Hint: 2-38 check whether the show rule matches its own output +#layout(_ => include "recursion.typ") + +--- recursion-show-math --- +// Test recursive show rules. +// Error: 22-25 maximum show rule depth exceeded +// Hint: 22-25 check whether the show rule matches its own output +#show math.equation: $x$ +$ x $ diff --git a/tests/suite/scripting/return.typ b/tests/suite/scripting/return.typ new file mode 100644 index 00000000..63e1c0b9 --- /dev/null +++ b/tests/suite/scripting/return.typ @@ -0,0 +1,87 @@ +// Test return out of functions. + +--- return-with-value --- +// Test return with value. +#let f(x) = { + return x + 1 +} + +#test(f(1), 2) + +--- return-join --- +// Test return with joining. + +#let f(x) = { + "a" + if x == 0 { + return "b" + } else if x == 1 { + "c" + } else { + "d" + return + "e" + } +} + +#test(f(0), "b") +#test(f(1), "ac") +#test(f(2), "ad") + +--- return-in-nested-content-block --- +// Test return with joining and content. + +#let f(text, caption: none) = { + text + if caption == none [\.#return] + [, ] + emph(caption) + [\.] +} + +#f(caption: [with caption])[My figure] + +#f[My other figure] + +--- return-outside-of-function --- +// Test return outside of function. + +#for x in range(5) { + // Error: 3-9 cannot return outside of function + return +} + +--- return-in-first-arg --- +// Test that the expression is evaluated to the end. +#let sum(..args) = { + let s = 0 + for v in args.pos() { + s += v + } + s +} + +#let f() = { + sum(..return, 1, 2, 3) + "nope" +} + +#test(f(), 6) + +--- return-in-content-block --- +// Test value return from content. +#let x = 3 +#let f() = [ + Hello 😀 + #return "nope" + World +] + +#test(f(), "nope") + +--- return-semicolon-or-linebreak --- +// Test rejection of extra value +#let f() = [ + // Error: 16-16 expected semicolon or line break + #return a + b Hello World +] diff --git a/tests/suite/scripting/while.typ b/tests/suite/scripting/while.typ new file mode 100644 index 00000000..5e452a89 --- /dev/null +++ b/tests/suite/scripting/while.typ @@ -0,0 +1,59 @@ +// Test while expressions. + +--- while-loop-basic --- +// Should output `2 4 6 8 10`. +#let i = 0 +#while i < 10 [ + #(i += 2) + #i +] + +// Should output `Hi`. +#let iter = true +#while iter { + iter = false + "Hi." +} + +#while false { + dont-care +} + +--- while-loop-expr --- +// Value of while loops. + +#test(while false {}, none) + +#let i = 0 +#test(type(while i < 1 [#(i += 1)]), content) + +--- while-loop-condition-content-invalid --- +// Condition must be boolean. +// Error: 8-14 expected boolean, found content +#while [nope] [nope] + +--- while-loop-condition-always-true --- +// Error: 8-25 condition is always true +#while 2 < "hello".len() {} + +--- while-loop-limit --- +// Error: 2:2-2:24 loop seems to be infinite +#let i = 1 +#while i > 0 { i += 1 } + +--- while-loop-incomplete --- +// Error: 7 expected expression +#while + +// Error: 8 expected expression +#{while} + +// Error: 9 expected block +#while x + +// Error: 7 expected expression +#while +x {} + +// Error: 9 expected block +#while x something diff --git a/tests/suite/styling/fold.typ b/tests/suite/styling/fold.typ new file mode 100644 index 00000000..26fe991b --- /dev/null +++ b/tests/suite/styling/fold.typ @@ -0,0 +1,19 @@ +--- fold-vec-order-text-features --- +// Test fold order of vectors. +#set text(features: (liga: 1)) +#set text(features: (liga: 0)) +fi + +--- fold-vec-order-text-decos --- +#underline(stroke: aqua + 4pt)[ + #underline[Hello] +] + +--- fold-vec-order-meta --- +#let c = counter("mycounter") +#c.update(1) +#locate(loc => [ + #c.update(2) + #c.at(loc) \ + Second: #locate(loc => c.at(loc)) +]) diff --git a/tests/suite/styling/set.typ b/tests/suite/styling/set.typ new file mode 100644 index 00000000..a31cd165 --- /dev/null +++ b/tests/suite/styling/set.typ @@ -0,0 +1,96 @@ +// General tests for set. + +--- set-instantiation-site --- +// Test that text is affected by instantiation-site bold. +#let x = [World] +Hello *#x* + +--- set-instantiation-site-markup --- +// Test that lists are affected by correct indents. +#let fruit = [ + - Apple + - Orange + #list(body-indent: 20pt)[Pear] +] + +- Fruit +#[#set list(indent: 10pt) + #fruit] +- No more fruit + +--- set-text-override --- +// Test that that block spacing and text style are respected from +// the outside, but the more specific fill is respected. +#set block(spacing: 4pt) +#set text(style: "italic", fill: eastern) +#let x = [And the forest #parbreak() lay silent!] +#text(fill: forest, x) + +--- set-scoped-in-code-block --- +// Test that scoping works as expected. +#{ + if true { + set text(blue) + [Blue ] + } + [Not blue] +} + +--- closure-path-resolve-in-layout-phase --- +// Test relative path resolving in layout phase. +#let choice = ("monkey.svg", "rhino.png", "tiger.jpg") +#set enum(numbering: n => { + let path = "/assets/images/" + choice.at(n - 1) + move(dy: -0.15em, image(path, width: 1em, height: 1em)) +}) + ++ Monkey ++ Rhino ++ Tiger + +--- set-if --- +// Test conditional set. +#show ref: it => { + set text(red) if it.target == <unknown> + "@" + str(it.target) +} + +@hello from the @unknown + +--- set-if-bad-type --- +// Error: 19-24 expected boolean, found integer +#set text(red) if 1 + 2 + +--- set-in-expr --- +// Error: 12-26 set is only allowed directly in code and content blocks +#{ let x = set text(blue) } + +--- set-vs-construct-1 --- +// Ensure that constructor styles aren't passed down the tree. +// The inner list should have no extra indent. +#set par(leading: 2pt) +#list(body-indent: 20pt, [First], list[A][B]) + +--- set-vs-construct-2 --- +// Ensure that constructor styles win, but not over outer styles. +// The outer paragraph should be right-aligned, +// but the B should be center-aligned. +#set list(marker: [>]) +#list(marker: [--])[ + #rect(width: 2cm, fill: conifer, inset: 4pt, list[A]) +] + +--- set-vs-construct-3 --- +// The inner rectangle should also be yellow here. +// (and therefore invisible) +#[#set rect(fill: yellow);#text(1em, rect(inset: 5pt, rect()))] + +--- set-vs-construct-4 --- +// The inner rectangle should not be yellow here. +A #box(rect(fill: yellow, inset: 5pt, rect())) B + +--- show-set-vs-construct --- +// The constructor property should still work +// when there are recursive show rules. +#show enum: set text(blue) +#enum(numbering: "(a)", [A], enum[B]) diff --git a/tests/suite/styling/show-set.typ b/tests/suite/styling/show-set.typ new file mode 100644 index 00000000..ea788c93 --- /dev/null +++ b/tests/suite/styling/show-set.typ @@ -0,0 +1,70 @@ +// Test show-set rules. + +--- show-set-override --- +// Test overriding show-set rules. +#show strong: set text(red) +Hello *World* + +#show strong: set text(blue) +Hello *World* + +--- show-set-on-same-element --- +// Test show-set rule on the same element. +#set figure(supplement: [Default]) +#show figure.where(kind: table): set figure(supplement: [Tableau]) +#figure( + table(columns: 2)[A][B][C][D], + caption: [Four letters], +) + +--- show-set-same-element-and-order --- +// Test both things at once. +#show heading: set text(red) += Level 1 +== Level 2 + +#show heading.where(level: 1): set text(blue) +#show heading.where(level: 1): set text(green) +#show heading.where(level: 1): set heading(numbering: "(I)") += Level 1 +== Level 2 + +--- show-set-same-element-matched-field --- +// Test setting the thing we just matched on. +// This is quite cursed, but it works. +#set heading(numbering: "(I)") +#show heading.where(numbering: "(I)"): set heading(numbering: "1.") += Heading + +--- show-set-same-element-synthesized-matched-field --- +// Same thing, but even more cursed, because `kind` is synthesized. +#show figure.where(kind: table): set figure(kind: raw) +#figure(table[A], caption: [Code]) + +--- show-set-same-element-matching-interaction --- +// Test that show-set rules on the same element don't affect each other. This +// could be implemented, but isn't as of yet. +#show heading.where(level: 1): set heading(numbering: "(I)") +#show heading.where(numbering: "(I)"): set text(red) += Heading + +--- show-set-on-layoutable-element --- +// Test show-set rules on layoutable element to ensure it is realized +// even though it implements `LayoutMultiple`. +#show table: set text(red) +#pad(table(columns: 4)[A][B][C][D]) + +--- show-function-order-with-set --- +// These are both red because in the expanded form, `set text(red)` ends up +// closer to the content than `set text(blue)`. +#show strong: it => { set text(red); it } +Hello *World* + +#show strong: it => { set text(blue); it } +Hello *World* + +--- show-function-set-on-it --- +// This doesn't have an effect. An element is materialized before any show +// rules run. +#show heading: it => { set heading(numbering: "(I)"); it } += Heading diff --git a/tests/suite/styling/show-text.typ b/tests/suite/styling/show-text.typ new file mode 100644 index 00000000..56b659b2 --- /dev/null +++ b/tests/suite/styling/show-text.typ @@ -0,0 +1,133 @@ +// Test text replacement show rules. + +--- show-text-basic --- +// Test classic example. +#set text(font: "Roboto") +#show "Der Spiegel": smallcaps +Die Zeitung Der Spiegel existiert. + +--- show-text-regex --- +// Another classic example. +#show "TeX": [T#h(-0.145em)#box(move(dy: 0.233em)[E])#h(-0.135em)X] +#show regex("(Lua)?(La)?TeX"): name => box(text(font: "New Computer Modern")[#name]) + +TeX, LaTeX, LuaTeX and LuaLaTeX! + +--- show-text-cyclic --- +// Test direct cycle. +#show "Hello": text(red)[Hello] +Hello World! + +--- show-text-cyclic-raw --- +// Test replacing text with raw text. +#show "rax": `rax` +The register rax. + +--- show-text-indirectly-cyclic --- +// Test indirect cycle. +#show "Good": [Typst!] +#show "Typst": [Fun!] +#show "Fun": [Good!] + +#set text(ligatures: false) +Good \ +Fun \ +Typst \ + +--- show-text-exactly-once --- +// Test that replacements happen exactly once. +#show "A": [BB] +#show "B": [CC] +AA (8) + +--- show-text-regex-word-boundary --- +// Test caseless match and word boundaries. +#show regex("(?i)\bworld\b"): [🌍] + +Treeworld, the World of worlds, is a world. + +--- show-text-empty --- +// Test there is no crashing on empty strings +// Error: 1:7-1:9 text selector is empty +#show "": [] + +--- show-text-regex-empty --- +// Error: 1:7-1:16 regex selector is empty +#show regex(""): [AA] + +--- show-text-regex-matches-empty --- +// Error: 1:7-1:42 regex matches empty text +#show regex("(VAR_GLOBAL|END_VAR||BOOL)") : [] + +--- show-text-regex-character-class --- +// This is a fun one. +#set par(justify: true) +#show regex("\S"): letter => box(stroke: 1pt, inset: 2pt, upper(letter)) +#lorem(5) + +--- show-text-regex-case-insensitive --- +// See also: https://github.com/mTvare6/hello-world.rs +#show regex("(?i)rust"): it => [#it (🚀)] +Rust is memory-safe and blazingly fast. Let's rewrite everything in rust. + +--- show-text-get-text-on-it --- +// Test accessing the string itself. +#show "hello": it => it.text.split("").map(upper).join("|") +Oh, hello there! + +--- show-text-in-other-show --- +// Replace worlds but only in lists. +#show list: it => [ + #show "World": [🌎] + #it +] + +World +- World + +--- show-text-path-resolving --- +// Test absolute path in layout phase. + +#show "GRAPH": image("/assets/images/graph.png") + +The GRAPH has nodes. + +--- show-set-text-order-adjacent-1 --- +#show "He": set text(red) +#show "ya": set text(blue) +Heya + +--- show-set-text-order-contained-1 --- +#show "Heya": set text(red) +#show "ya": set text(blue) +Heya + +--- show-set-text-order-contained-3 --- +#show "He": set text(red) +#show "Heya": set text(blue) +Heya + +--- show-set-text-order-overlapping-1 --- +#show "Heya": set text(red) +#show "yaho": set text(blue) +Heyaho + +--- show-set-text-order-adjacent-2 --- +#show "He": set text(red) +#show "ya": set text(weight: "bold") +Heya + +--- show-set-text-order-contained-2 --- +#show "Heya": set text(red) +#show "ya": set text(weight: "bold") +Heya + +--- show-set-text-order-contained-4 --- +#show "He": set text(red) +#show "Heya": set text(weight: "bold") +Heya + +--- show-set-text-order-overlapping-2 --- +#show "Heya": set text(red) +#show "yaho": set text(weight: "bold") +Heyaho diff --git a/tests/suite/styling/show-where.typ b/tests/suite/styling/show-where.typ new file mode 100644 index 00000000..72dbae69 --- /dev/null +++ b/tests/suite/styling/show-where.typ @@ -0,0 +1,89 @@ +--- show-where-optional-field-raw --- +// Test that where selectors also trigger on set rule fields. +#show raw.where(block: false): box.with( + fill: luma(220), + inset: (x: 3pt, y: 0pt), + outset: (y: 3pt), + radius: 2pt, +) + +This is #raw("fn main() {}") some text. + +--- show-where-optional-field-text --- +// Note: This show rule is horribly inefficient because it triggers for +// every individual text element. But it should still work. +#show text.where(lang: "de"): set text(red) + +#set text(lang: "es") +Hola, mundo! + +#set text(lang: "de") +Hallo Welt! + +#set text(lang: "en") +Hello World! + +--- show-where-folding-text-size --- +// Test that folding is taken into account. +#set text(5pt) +#set text(2em) + +#[ + #show text.where(size: 2em): set text(blue) + 2em not blue +] + +#[ + #show text.where(size: 10pt): set text(blue) + 10pt blue +] + +--- show-where-folding-stroke --- +// Test again that folding is taken into account. +#set rect(width: 40pt, height: 10pt) +#set rect(stroke: blue) +#set rect(stroke: 2pt) + +#{ + show rect.where(stroke: blue): "Not Triggered" + rect() +} +#{ + show rect.where(stroke: 2pt): "Not Triggered" + rect() +} +#{ + show rect.where(stroke: 2pt + blue): "Triggered" + rect() +} + +--- show-where-resolving-length --- +// Test that resolving is *not* taken into account. +#set line(start: (1em, 1em + 2pt)) + +#{ + show line.where(start: (1em, 1em + 2pt)): "Triggered" + line() +} +#{ + show line.where(start: (10pt, 12pt)): "Not Triggered" + line() +} + + +--- show-where-resolving-hyphenate --- +// Test again that resolving is *not* taken into account. +#set text(hyphenate: auto) + +#[ + #show text.where(hyphenate: auto): underline + Auto +] +#[ + #show text.where(hyphenate: true): underline + True +] +#[ + #show text.where(hyphenate: false): underline + False +] diff --git a/tests/suite/styling/show.typ b/tests/suite/styling/show.typ new file mode 100644 index 00000000..aa121bff --- /dev/null +++ b/tests/suite/styling/show.typ @@ -0,0 +1,262 @@ +// Test show rules. + +--- show-selector-basic --- +// Override lists. +#show list: it => "(" + it.children.map(v => v.body).join(", ") + ")" + +- A + - B + - C +- D +- E + +--- show-selector-replace-and-show-set --- +// Test full reset. +#show heading: [B] +#show heading: set text(size: 10pt, weight: 400) +A #[= Heading] C + +--- show-selector-discard --- +// Test full removal. +#show heading: none + +Where is += There are no headings around here! +my heading? + +--- show-selector-realistic --- +// Test integrated example. +#show heading: it => block({ + set text(10pt) + box(move(dy: -1pt)[📖]) + h(5pt) + if it.level == 1 { + underline(text(1.25em, blue, it.body)) + } else { + text(red, it.body) + } +}) + += Task 1 +Some text. + +== Subtask +Some more text. + += Task 2 +Another text. + +--- show-in-show --- +// Test set and show in code blocks. +#show heading: it => { + set text(red) + show "ding": [🛎] + it.body +} + += Heading + +--- show-nested-scopes --- +// Test that scoping works as expected. +#{ + let world = [ World ] + show "W": strong + world + { + set text(blue) + show: it => { + show "o": "Ø" + it + } + world + } + world +} + +--- show-selector-replace --- +#show heading: [1234] += Heading + +--- show-unknown-field --- +// Error: 25-29 content does not contain field "page" +#show heading: it => it.page += Heading + +--- show-text-element-discard --- +#show text: none +Hey + +--- show-selector-not-an-element-function --- +// Error: 7-12 only element functions can be used as selectors +#show upper: it => {} + +--- show-bad-replacement-type --- +// Error: 16-20 expected content or function, found integer +#show heading: 1234 += Heading + +--- show-bad-selector-type --- +// Error: 7-10 expected symbol, string, label, function, regex, or selector, found color +#show red: [] + +--- show-selector-in-expression --- +// Error: 7-25 show is only allowed directly in code and content blocks +#(1 + show heading: none) + +--- show-bare-basic --- +#set page(height: 130pt) +#set text(0.7em) + +#align(center)[ + #text(1.3em)[*Essay on typography*] \ + T. Ypst +] + +#show: columns.with(2) +Great typography is at the essence of great storytelling. It is the medium that +transports meaning from parchment to reader, the wave that sparks a flame +in booklovers and the great fulfiller of human need. + +--- show-bare-content-block --- +// Test bare show in content block. +A #[_B #show: c => [*#c*]; C_] D + +--- show-bare-vs-set-text --- +// Test style precedence. +#set text(fill: eastern, size: 1.5em) +#show: text.with(fill: forest) +Forest + +--- show-bare-replace-with-content --- +#show: [Shown] +Ignored + +--- show-bare-in-expression --- +// Error: 4-19 show is only allowed directly in code and content blocks +#((show: body => 2) * body) + +--- show-bare-missing-colon-closure --- +// Error: 6 expected colon +#show it => {} + +--- show-bare-missing-colon --- +// Error: 6 expected colon +#show it + +--- show-recursive-identity --- +// Test basic identity. +#show heading: it => it += Heading + +--- show-multiple-rules --- +// Test more recipes down the chain. +#show list: scale.with(origin: left, x: 80%) +#show heading: [] +#show enum: [] +- Actual +- Tight +- List += Nope + +--- show-rule-in-function --- +// Test show rule in function. +#let starwars(body) = { + show list: it => block({ + stack(dir: ltr, + text(red, it), + 1fr, + scale(x: -100%, text(blue, it)), + ) + }) + body +} + +- Normal list + +#starwars[ + - Star + - Wars + - List +] + +- Normal list + +--- show-recursive-multiple --- +// Test multi-recursion with nested lists. +#set rect(inset: 3pt) +#show list: rect.with(stroke: blue) +#show list: rect.with(stroke: red) +#show list: block + +- List + - Nested + - List +- Recursive! + +--- show-selector-where --- +// Inline code. +#show raw.where(block: false): box.with( + radius: 2pt, + outset: (y: 2.5pt), + inset: (x: 3pt, y: 0pt), + fill: luma(230), +) + +// Code blocks. +#show raw.where(block: true): block.with( + outset: -3pt, + inset: 11pt, + fill: luma(230), + stroke: (left: 1.5pt + luma(180)), +) + +#set page(margin: (top: 12pt)) +#set par(justify: true) + +This code tests `code` +with selectors and justification. + +```rs +code!("it"); +``` + +You can use the ```rs *const T``` pointer or +the ```rs &mut T``` reference. + +--- show-set-where-override --- +#show heading: set text(green) +#show heading.where(level: 1): set text(red) +#show heading.where(level: 2): set text(blue) += Red +== Blue +=== Green + +--- show-selector-or-elements-with-set --- +// Looking forward to `heading.where(level: 1 | 2)` :) +#show heading.where(level: 1).or(heading.where(level: 2)): set text(red) += L1 +== L2 +=== L3 +==== L4 + +--- show-selector-element-or-label --- +// Test element selector combined with label selector. +#show selector(strong).or(<special>): highlight +I am *strong*, I am _emphasized_, and I am #[special<special>]. + +--- show-selector-element-or-text --- +// Ensure that text selector cannot be nested in and/or. That's too complicated, +// at least for now. + +// Error: 7-41 this selector cannot be used with show +#show heading.where(level: 1).or("more"): set text(red) + +--- show-delayed-error --- +// Error: 21-34 panicked with: "hey1" +#show heading: _ => panic("hey1") + +// Error: 20-33 panicked with: "hey2" +#show strong: _ => panic("hey2") + += Hello +*strong* diff --git a/tests/suite/symbols/symbol.typ b/tests/suite/symbols/symbol.typ new file mode 100644 index 00000000..8f9a49ca --- /dev/null +++ b/tests/suite/symbols/symbol.typ @@ -0,0 +1,38 @@ +// Test symbols. + +--- symbol --- +#emoji.face +#emoji.woman.old +#emoji.turtle + +#set text(font: "New Computer Modern Math") +#sym.arrow +#sym.arrow.l +#sym.arrow.r.squiggly +#sym.arrow.tr.hook + +#sym.arrow.r;this and this#sym.arrow.l; + +--- symbol-constructor --- +#let envelope = symbol( + "🖂", + ("stamped", "🖃"), + ("stamped.pen", "🖆"), + ("lightning", "🖄"), + ("fly", "🖅"), +) + +#envelope +#envelope.stamped +#envelope.pen +#envelope.stamped.pen +#envelope.lightning +#envelope.fly + +--- symbol-constructor-empty --- +// Error: 2-10 expected at least one variant +#symbol() + +--- symbol-unknown-modifier --- +// Error: 13-20 unknown symbol modifier +#emoji.face.garbage diff --git a/tests/suite/syntax/backtracking.typ b/tests/suite/syntax/backtracking.typ new file mode 100644 index 00000000..33f05770 --- /dev/null +++ b/tests/suite/syntax/backtracking.typ @@ -0,0 +1,32 @@ +// Ensure that parser backtracking doesn't lead to exponential time consumption. +// If this regresses, the test suite will not terminate, which is a bit +// unfortunate compared to a good error, but at least we know something is up. +// + +--- parser-backtracking-param-default-value --- +#{ + let s = "(x: 1) => x" + let pat = "(x: {}) => 1 + x()" + for _ in range(50) { + s = pat.replace("{}", s) + } + test(eval(s)(), 51) +} + +--- parser-backtracking-destructuring-assignment --- +#{ + let s = "(x) = 1" + let pat = "(x: {_}) = 1" + for _ in range(100) { + s = pat.replace("_", s) + } + // Error: 8-9 cannot destructure integer + eval(s) +} + +--- parser-backtracking-destructuring-whitespace --- +// Test whitespace after memoized part. +#( (x: () => 1 ) => 1 ) +// ------- +// This is memoized and we want to ensure that whitespace after this +// is handled correctly. diff --git a/tests/suite/syntax/comment.typ b/tests/suite/syntax/comment.typ new file mode 100644 index 00000000..ac3e1943 --- /dev/null +++ b/tests/suite/syntax/comment.typ @@ -0,0 +1,43 @@ +// Test line and block comments. + +--- comments --- +// Line comment acts as spacing. +A// you +B + +// Block comment does not act as spacing, nested block comments. +C/* + /* */ +*/D + +// Works in code. +#test(type(/*1*/ 1) // +, int) + +// End of block comment in line comment. +// Hello */ + +// Nested "//" doesn't count as line comment. +/* // */ +E + +/*//*/ +This is a comment. +*/*/ + +--- comment-end-of-line --- +// Test comments at the end of a line +First part// +Second part + +// Test comments at the end of a line with pre-spacing +First part // +Second part + +--- comment-block-unclosed --- +// End should not appear without start. +// Error: 7-9 unexpected end of block comment +/* */ */ + +// Unterminated is okay. +/* diff --git a/tests/suite/syntax/embedded.typ b/tests/suite/syntax/embedded.typ new file mode 100644 index 00000000..74ce4a03 --- /dev/null +++ b/tests/suite/syntax/embedded.typ @@ -0,0 +1,9 @@ +// Test embedded expressions. + +--- markup-expr-incomplete --- +// Error: 2-2 expected expression +# + +--- markup-expr-incomplete-followed-by-text --- +// Error: 2-2 expected expression +# hello diff --git a/tests/suite/syntax/escape.typ b/tests/suite/syntax/escape.typ new file mode 100644 index 00000000..ff05aa99 --- /dev/null +++ b/tests/suite/syntax/escape.typ @@ -0,0 +1,36 @@ +// Test escape sequences. + +--- escape --- +// Escapable symbols. +\\ \/ \[ \] \{ \} \# \* \_ \+ \= \~ \ +\` \$ \" \' \< \> \@ \( \) \A + +// No need to escape. +( ) ; + +// Escaped comments. +\// +\/\* \*\/ +\/* \*/ * + +// Unicode escape sequence. +\u{1F3D5} == 🏕 + +// Escaped escape sequence. +\u{41} vs. \\u\{41\} + +// Some code stuff in text. +let f() , ; : | + - /= == 12 "string" + +// Escaped dot. +10\. May + +--- escape-invalid-codepoint --- +// Unicode codepoint does not exist. +// Error: 1-11 invalid Unicode codepoint: FFFFFF +\u{FFFFFF} + +--- escape-unclosed --- +// Unterminated. +// Error: 1-6 unclosed Unicode escape sequence +\u{41[*Bold*] diff --git a/tests/suite/syntax/newlines.typ b/tests/suite/syntax/newlines.typ new file mode 100644 index 00000000..eef45619 --- /dev/null +++ b/tests/suite/syntax/newlines.typ @@ -0,0 +1,77 @@ +// Test newline continuations. + +--- newline-continuation-code --- +#{ + "hello" + .clusters() + if false { + + } + else { + ("1", "2") + } +} + +--- newline-continuation-markup --- +#"hello" + .codepoints() + +#if false { + +} +else { + ("1", "2") +} + +--- newline-continuation-method-blank --- +#test({ + "hi 1" + + .clusters() +}, ("h", "i", " ", "1")) + +--- newline-continuation-method-line-comment-after --- +#test({ + "hi 2"// comment + .clusters() +}, ("h", "i", " ", "2")) + +--- newline-continuation-method-block-comment-after --- +#test({ + "hi 3"/* comment */ + .clusters() +}, ("h", "i", " ", "3")) + +--- newline-continuation-method-line-comment-between --- +#test({ + "hi 4" + // comment + .clusters() +}, ("h", "i", " ", "4")) + +--- newline-continuation-method-block-comment-between --- +#test({ + "hi 5" + /*comment*/.clusters() +}, ("h", "i", " ", "5")) + +--- newline-continuation-method-comments-and-blanks --- +#test({ + "hi 6" + // comment + + + /* comment */ + .clusters() +}, ("h", "i", " ", "6")) + +--- newline-continuation-if-else-comment --- +#test({ + let foo(x) = { + if x < 0 { "negative" } + // comment + else { "non-negative" } + } + + foo(1) +}, "non-negative") diff --git a/tests/suite/syntax/numbers.typ b/tests/suite/syntax/numbers.typ new file mode 100644 index 00000000..1f15ac72 --- /dev/null +++ b/tests/suite/syntax/numbers.typ @@ -0,0 +1,32 @@ +// Test how numbers are displayed. + +--- numbers --- +// Test numbers in text mode. +12 \ +12.0 \ +3.14 \ +1234567890 \ +0123456789 \ +0 \ +0.0 \ ++0 \ ++0.0 \ +-0 \ +-0.0 \ +-1 \ +-3.14 \ +-9876543210 \ +-0987654321 \ +٣٫١٤ \ +-٣٫١٤ \ +-¾ \ +#text(fractions: true)[-3/2] \ +2022 - 2023 \ +2022 -- 2023 \ +2022--2023 \ +2022-2023 \ +٢٠٢٢ - ٢٠٢٣ \ +٢٠٢٢ -- ٢٠٢٣ \ +٢٠٢٢--٢٠٢٣ \ +٢٠٢٢-٢٠٢٣ \ +-500 -- -400 diff --git a/tests/suite/syntax/shorthand.typ b/tests/suite/syntax/shorthand.typ new file mode 100644 index 00000000..81aa6b7b --- /dev/null +++ b/tests/suite/syntax/shorthand.typ @@ -0,0 +1,61 @@ +// Test shorthands for unicode codepoints. + +--- shorthand-nbsp-and-shy-hyphen --- +The non-breaking space~does work, soft-?hyphen also does. + +--- shorthand-nbsp-width --- +// Make sure non-breaking and normal space always +// have the same width. Even if the font decided +// differently. +#set text(font: "New Computer Modern") +a b \ +a~b + +--- shorthand-dashes --- +- En dash: -- +- Em dash: --- + +--- shorthand-ellipsis --- +#set text(font: "Roboto") +A... vs #"A..." + +--- shorthands-math --- +// Check all math shorthands +$...$\ +$-$\ +$'$\ +$*$\ +$!=$\ +$:=$\ +$::=$\ +$=:$\ +$<<$\ +$<<<$\ +$>>$\ +$>>>$\ +$<=$\ +$>=$\ +$->$\ +$-->$\ +$|->$\ +$>->$\ +$->>$\ +$<-$\ +$<--$\ +$<-<$\ +$<<-$\ +$<->$\ +$<-->$\ +$~>$\ +$~~>$\ +$<~$\ +$<~~$\ +$=>$\ +$|=>$\ +$==>$\ +$<==$\ +$<=>$\ +$<==>$\ +$[|$\ +$|]$\ +$||$ diff --git a/tests/suite/text/case.typ b/tests/suite/text/case.typ new file mode 100644 index 00000000..2bf68bc3 --- /dev/null +++ b/tests/suite/text/case.typ @@ -0,0 +1,11 @@ +// Test the `upper` and `lower` functions. + +--- lower-and-upper --- +#let memes = "ArE mEmEs gReAt?"; +#test(lower(memes), "are memes great?") +#test(upper(memes), "ARE MEMES GREAT?") +#test(upper("Ελλάδα"), "ΕΛΛΆΔΑ") + +--- upper-bad-type --- +// Error: 8-9 expected string or content, found integer +#upper(1) diff --git a/tests/suite/text/coma.typ b/tests/suite/text/coma.typ new file mode 100644 index 00000000..df757633 --- /dev/null +++ b/tests/suite/text/coma.typ @@ -0,0 +1,26 @@ +--- coma --- +// LARGE +#set page(width: 450pt, margin: 1cm) + +*Technische Universität Berlin* #h(1fr) *WiSe 2019/2020* \ +*Fakultät II, Institut for Mathematik* #h(1fr) Woche 3 \ +Sekretariat MA \ +Dr. Max Mustermann \ +Ola Nordmann, John Doe + +#v(3mm) +#align(center)[ + #set par(leading: 3mm) + #text(1.2em)[*3. Übungsblatt Computerorientierte Mathematik II*] \ + *Abgabe: 03.05.2019* (bis 10:10 Uhr in MA 001) \ + *Alle Antworten sind zu beweisen.* +] + +*1. Aufgabe* #h(1fr) (1 + 1 + 2 Punkte) + +Ein _Binärbaum_ ist ein Wurzelbaum, in dem jeder Knoten ≤ 2 Kinder hat. +Die Tiefe eines Knotens _v_ ist die Länge des eindeutigen Weges von der Wurzel +zu _v_, und die Höhe von _v_ ist die Länge eines längsten (absteigenden) Weges +von _v_ zu einem Blatt. Die Höhe des Baumes ist die Höhe der Wurzel. + +#align(center, image("/assets/images/graph.png", width: 75%)) diff --git a/tests/suite/text/copy-paste.typ b/tests/suite/text/copy-paste.typ new file mode 100644 index 00000000..ff6da893 --- /dev/null +++ b/tests/suite/text/copy-paste.typ @@ -0,0 +1,8 @@ +// Test copy-paste and search in PDF with ligatures +// and Arabic test. Must be tested manually! + +--- text-copy-paste-ligatures --- +The after fira 🏳️🌈! + +#set text(lang: "ar", font: "Noto Sans Arabic") +مرحبًا diff --git a/tests/suite/text/deco.typ b/tests/suite/text/deco.typ new file mode 100644 index 00000000..07fdb6c1 --- /dev/null +++ b/tests/suite/text/deco.typ @@ -0,0 +1,85 @@ +// Test text decorations. + +--- underline-overline-strike --- +#let red = rgb("fc0030") + +// Basic strikethrough. +#strike[Statements dreamt up by the utterly deranged.] + +// Move underline down. +#underline(offset: 5pt)[Further below.] + +// Different color. +#underline(stroke: red, evade: false)[Critical information is conveyed here.] + +// Inherits font color. +#text(fill: red, underline[Change with the wind.]) + +// Both over- and underline. +#overline(underline[Running amongst the wolves.]) + +--- strike-with --- +#let redact = strike.with(stroke: 10pt, extent: 0.05em) +#let highlight-custom = strike.with(stroke: 10pt + rgb("abcdef88"), extent: 0.05em) + +// Abuse thickness and transparency for redacting and highlighting stuff. +Sometimes, we work #redact[in secret]. +There might be #highlight-custom[redacted] things. + +--- underline-stroke-folding --- +// Test stroke folding. +#set underline(stroke: 2pt, offset: 2pt) +#underline(text(red, [DANGER!])) + +--- underline-background --- +// Test underline background +#set underline(background: true, stroke: (thickness: 0.5em, paint: red, cap: "round")) +#underline[This is in the background] + +--- overline-background --- +// Test overline background +#set overline(background: true, stroke: (thickness: 0.5em, paint: red, cap: "round")) +#overline[This is in the background] + +--- strike-background --- +// Test strike background +#set strike(background: true, stroke: 5pt + red) +#strike[This is in the background] + +--- highlight --- +// Test highlight. +This is the built-in #highlight[highlight with default color]. +We can also specify a customized value +#highlight(fill: green.lighten(80%))[to highlight]. + +--- highlight-bounds --- +// Test default highlight bounds. +#highlight[ace], +#highlight[base], +#highlight[super], +#highlight[phone #sym.integral] + +--- highlight-edges --- +// Test a tighter highlight. +#set highlight(top-edge: "x-height", bottom-edge: "baseline") +#highlight[ace], +#highlight[base], +#highlight[super], +#highlight[phone #sym.integral] + +--- highlight-edges-bounds --- +// Test a bounds highlight. +#set highlight(top-edge: "bounds", bottom-edge: "bounds") +#highlight[abc] +#highlight[abc #sym.integral] + +--- highlight-radius --- +// Test highlight radius +#highlight(radius: 3pt)[abc], +#highlight(radius: 1em)[#lorem(5)] + +--- highlight-stroke --- +// Test highlight stroke +#highlight(stroke: 2pt + blue)[abc] +#highlight(stroke: (top: blue, left: red, bottom: green, right: orange))[abc] +#highlight(stroke: 1pt, radius: 3pt)[#lorem(5)] diff --git a/tests/suite/text/edge.typ b/tests/suite/text/edge.typ new file mode 100644 index 00000000..57732156 --- /dev/null +++ b/tests/suite/text/edge.typ @@ -0,0 +1,39 @@ +// Test top and bottom text edge. + +--- text-edge --- +#set page(width: 160pt) +#set text(size: 8pt) + +#let try(top, bottom) = rect(inset: 0pt, fill: conifer)[ + #set text(font: "IBM Plex Mono", top-edge: top, bottom-edge: bottom) + From #top to #bottom +] + +#let try-bounds(top, bottom) = rect(inset: 0pt, fill: conifer)[ + #set text(font: "IBM Plex Mono", top-edge: top, bottom-edge: bottom) + #top to #bottom: "yay, Typst" +] + +#try("ascender", "descender") +#try("ascender", "baseline") +#try("cap-height", "baseline") +#try("x-height", "baseline") +#try-bounds("cap-height", "baseline") +#try-bounds("bounds", "baseline") +#try-bounds("bounds", "bounds") +#try-bounds("x-height", "bounds") + +#try(4pt, -2pt) +#try(1pt + 0.3em, -0.15em) + +--- text-edge-bad-type --- +// Error: 21-23 expected "ascender", "cap-height", "x-height", "baseline", "bounds", or length, found array +#set text(top-edge: ()) + +--- text-edge-bad-value --- +// Error: 24-26 expected "baseline", "descender", "bounds", or length +#set text(bottom-edge: "") + +--- text-edge-wrong-edge --- +// Error: 24-36 expected "baseline", "descender", "bounds", or length +#set text(bottom-edge: "cap-height") diff --git a/tests/suite/text/em.typ b/tests/suite/text/em.typ new file mode 100644 index 00000000..be7e3428 --- /dev/null +++ b/tests/suite/text/em.typ @@ -0,0 +1,33 @@ +// Test font-relative sizing. + +--- text-size-em-nesting --- +#set text(size: 5pt) +A // 5pt +#[ + #set text(size: 2em) + B // 10pt + #[ + #set text(size: 1.5em + 1pt) + C // 16pt + #text(size: 2em)[D] // 32pt + E // 16pt + ] + F // 10pt +] +G // 5pt + +--- text-size-em --- +// Test using ems in arbitrary places. +#set text(size: 5pt) +#set text(size: 2em) +#set square(fill: red) + +#let size = { + let size = 0.25em + 1pt + for _ in range(3) { + size *= 2 + } + size - 3pt +} + +#stack(dir: ltr, spacing: 1fr, square(size: size), square(size: 25pt)) diff --git a/tests/suite/text/font.typ b/tests/suite/text/font.typ new file mode 100644 index 00000000..47ec6419 --- /dev/null +++ b/tests/suite/text/font.typ @@ -0,0 +1,66 @@ +// Test configuring font properties. + +--- text-font-properties --- +// Set same font size in three different ways. +#text(20pt)[A] +#text(2em)[A] +#text(size: 15pt + 0.5em)[A] + +// Do nothing. +#text()[Normal] + +// Set style (is available). +#text(style: "italic")[Italic] + +// Set weight (is available). +#text(weight: "bold")[Bold] + +// Set stretch (not available, matching closest). +#text(stretch: 50%)[Condensed] + +// Set font family. +#text(font: "IBM Plex Serif")[Serif] + +// Emoji. +Emoji: 🐪, 🌋, 🏞 + +// Colors. +#[ + #set text(fill: eastern) + This is #text(rgb("FA644B"))[way more] colorful. +] + +// Transparency. +#block(fill: green)[ + #set text(fill: rgb("FF000080")) + This text is transparent. +] + +// Disable font fallback beyond the user-specified list. +// Without disabling, New Computer Modern Math would come to the rescue. +#set text(font: ("PT Sans", "Twitter Color Emoji"), fallback: false) +2π = 𝛼 + 𝛽. ✅ + +--- text-call-body --- +// Test string body. +#text("Text") \ +#text(red, "Text") \ +#text(font: "Ubuntu", blue, "Text") \ +#text([Text], teal, font: "IBM Plex Serif") \ +#text(forest, font: "New Computer Modern", [Text]) \ + +--- text-bad-argument --- +// Error: 11-16 unexpected argument +#set text(false) + +--- text-style-bad --- +// Error: 18-24 expected "normal", "italic", or "oblique" +#set text(style: "bold", weight: "thin") + +--- text-bad-extra-argument --- +// Error: 23-27 unexpected argument +#set text(size: 10pt, 12pt) + +--- text-bad-named-argument --- +// Error: 11-31 unexpected argument: something +#set text(something: "invalid") diff --git a/tests/suite/text/lang.typ b/tests/suite/text/lang.typ new file mode 100644 index 00000000..74f70140 --- /dev/null +++ b/tests/suite/text/lang.typ @@ -0,0 +1,74 @@ +// Test setting the document language. + +--- text-lang --- +// without any region +#set text(font: "Noto Serif CJK TC", lang: "zh") +#outline() + +--- text-lang-unknown-region --- +// with unknown region configured +#set text(font: "Noto Serif CJK TC", lang: "zh", region: "XX") +#outline() + +--- text-lang-region --- +// with region configured +#set text(font: "Noto Serif CJK TC", lang: "zh", region: "TW") +#outline() + +--- text-lang-hyphenate --- +// Ensure that setting the language does have effects. +#set text(hyphenate: true) +#grid( + columns: 2 * (20pt,), + gutter: 1fr, + text(lang: "en")["Eingabeaufforderung"], + text(lang: "de")["Eingabeaufforderung"], +) + +--- text-lang-shaping --- +// Test that the language passed to the shaper has an effect. +#set text(font: "Ubuntu") + +// Some lowercase letters are different in Serbian Cyrillic compared to other +// Cyrillic languages. Since there is only one set of Unicode codepoints for +// Cyrillic, these can only be seen when setting the language to Serbian and +// selecting one of the few fonts that support these letterforms. +Бб +#text(lang: "uk")[Бб] +#text(lang: "sr")[Бб] + +--- text-lang-script-shaping --- +// Verify that writing script/language combination has an effect +#{ + set text(size:20pt) + set text(script: "latn", lang: "en") + [Ş ] + set text(script: "latn", lang: "ro") + [Ş ] + set text(script: "grek", lang: "ro") + [Ş ] +} + +--- text-script-bad-type --- +// Error: 19-23 expected string or auto, found none +#set text(script: none) + +--- text-script-bad-value --- +// Error: 19-23 expected three or four letter script code (ISO 15924 or 'math') +#set text(script: "ab") + +--- text-lang-bad-type --- +// Error: 17-21 expected string, found none +#set text(lang: none) + +--- text-lang-bad-value --- +// Error: 17-20 expected two or three letter language code (ISO 639-1/2/3) +#set text(lang: "ӛ") + +--- text-lang-bad-value-emoji --- +// Error: 17-20 expected two or three letter language code (ISO 639-1/2/3) +#set text(lang: "😃") + +--- text-region-bad-value --- +// Error: 19-24 expected two letter region code (ISO 3166-1 alpha-2) +#set text(region: "hey") diff --git a/tests/suite/text/lorem.typ b/tests/suite/text/lorem.typ new file mode 100644 index 00000000..1524e2a3 --- /dev/null +++ b/tests/suite/text/lorem.typ @@ -0,0 +1,32 @@ +// Test blind text. + +--- lorem --- +// Test basic call. +#lorem(19) + +--- lorem-pars --- +// Test custom paragraphs with user code. +#set text(8pt) + +#{ + let sentences = lorem(59) + .split(".") + .filter(s => s != "") + .map(s => s + ".") + + let used = 0 + for s in sentences { + if used < 2 { + used += 1 + } else { + parbreak() + used = 0 + } + s.trim() + [ ] + } +} + +--- lorem-missing-words --- +// Error: 2-9 missing argument: words +#lorem() diff --git a/tests/suite/text/raw.typ b/tests/suite/text/raw.typ new file mode 100644 index 00000000..dce77fdb --- /dev/null +++ b/tests/suite/text/raw.typ @@ -0,0 +1,630 @@ +// Test raw blocks. + +--- raw-empty --- +// Empty raw block. +Empty raw block:``. + +--- raw-consecutive-single-backticks --- +// No extra space. +`A``B` + +--- raw-typst-lang --- +// Typst syntax inside. +```typ #let x = 1``` \ +```typ #f(1)``` + +--- raw-block-no-parbreaks --- +// Multiline block splits paragraphs. + +Text +```rust +fn code() {} +``` +Text + +--- raw-more-backticks --- +// Lots of backticks inside. +```` +```backticks``` +```` + +--- raw-trimming --- +// Trimming. + +// Space between "rust" and "let" is trimmed. +The keyword ```rust let```. + +// Trimming depends on number backticks. +(``) \ +(` untrimmed `) \ +(``` trimmed` ```) \ +(``` trimmed ```) \ +(``` trimmed```) \ + +--- raw-single-backtick-lang --- +// Single ticks should not have a language. +`rust let` + +--- raw-dedent-first-line --- +// First line is not dedented and leading space is still possible. + ``` A + B + C + ``` + +--- raw-dedent-empty-line --- +// Do not take empty lines into account when computing dedent. +``` + A + + B +``` + +--- raw-dedent-last-line --- +// Take last line into account when computing dedent. +``` + A + + B + ``` + +--- raw-tab-size --- +#set raw(tab-size: 8) + +```tsv +Year Month Day +2000 2 3 +2001 2 1 +2002 3 10 +``` + +--- raw-syntaxes --- +#set page(width: 180pt) +#set text(6pt) +#set raw(syntaxes: "/assets/syntaxes/SExpressions.sublime-syntax") + +```sexp +(defun factorial (x) + (if (zerop x) + ; with a comment + 1 + (* x (factorial (- x 1))))) +``` + + +--- raw-theme --- +// Test code highlighting with custom theme. +#set page(width: 180pt) +#set text(6pt) +#set raw(theme: "/assets/themes/halcyon.tmTheme") +#show raw: it => { + set text(fill: rgb("a2aabc")) + rect( + width: 100%, + inset: (x: 4pt, y: 5pt), + radius: 4pt, + fill: rgb("1d2433"), + place(right, text(luma(240), it.lang)) + it, + ) +} + +```typ += Chapter 1 +#lorem(100) + +#let hi = "Hello World" +#show heading: emph +``` + +--- raw-show-set --- +// Text show rule +#show raw: set text(font: "Roboto") +`Roboto` + +--- raw-align-default --- +// Text inside raw block should be unaffected by outer alignment by default. +#set align(center) +#set page(width: 180pt) +#set text(6pt) + +#lorem(20) + +```py +def something(x): + return x + +a = 342395823859823958329 +b = 324923 +``` + +#lorem(20) + +--- raw-align-specified --- +// Text inside raw block should follow the specified alignment. +#set page(width: 180pt) +#set text(6pt) + +#lorem(20) +#align(center, raw( + lang: "typ", + block: true, + align: right, + "#let f(x) = x\n#align(center, line(length: 1em))", +)) +#lorem(20) + +--- raw-align-invalid --- +// Error: 17-20 expected `start`, `left`, `center`, `right`, or `end`, found top +#set raw(align: top) + +--- raw-highlight-typ --- +// LARGE +#set page(width: auto) + +```typ +#set hello() +#set hello() +#set hello.world() +#set hello.my.world() +#let foo(x) = x * 2 +#show heading: func +#show module.func: func +#show module.func: it => {} +#foo(ident: ident) +#hello +#hello() +#box[] +#hello.world +#hello.world() +#hello().world() +#hello.my.world +#hello.my.world() +#hello.my().world +#hello.my().world() +#{ hello } +#{ hello() } +#{ hello.world() } +$ hello $ +$ hello() $ +$ box[] $ +$ hello.world $ +$ hello.world() $ +$ hello.my.world() $ +$ f_zeta(x), f_zeta(x)/1 $ +$ emph(hello.my.world()) $ +$ emph(hello.my().world) $ +$ emph(hello.my().world()) $ +$ #hello $ +$ #hello() $ +$ #hello.world $ +$ #hello.world() $ +$ #box[] $ +#if foo [] +``` + +--- raw-highlight --- +#set page(width: 180pt) +#set text(6pt) +#show raw: it => rect( + width: 100%, + inset: (x: 4pt, y: 5pt), + radius: 4pt, + fill: rgb(239, 241, 243), + place(right, text(luma(110), it.lang)) + it, +) + +```typ += Chapter 1 +#lorem(100) + +#let hi = "Hello World" +#show heading: emph +``` + +```rust +/// A carefully designed state machine. +#[derive(Debug)] +enum State<'a> { A(u8), B(&'a str) } + +fn advance(state: State<'_>) -> State<'_> { + unimplemented!("state machine") +} +``` + +```py +import this + +def hi(): + print("Hi!") +``` + +```cpp +#include <iostream> + +int main() { + std::cout << "Hello, world!"; +} +``` + +```julia +# Add two numbers +function add(x, y) + return x * y +end +``` + + // Try with some indent. + ```html + <!DOCTYPE html> + <html> + <head> + <meta charset="utf-8"> + </head> + <body> + <h1>Topic</h1> + <p>The Hypertext Markup Language.</p> + <script> + function foo(a, b) { + return a + b + "string"; + } + </script> + </body> + </html> + ``` + +--- raw-inline-multiline --- +#set page(width: 180pt) +#set text(6pt) +#set raw(lang:"python") + +Inline raws, multiline e.g. `for i in range(10): + # Only this line is a comment. + print(i)` or otherwise e.g. `print(j)`, are colored properly. + +Inline raws, multiline e.g. ` +# Appears blocky due to linebreaks at the boundary. +for i in range(10): + print(i) +` or otherwise e.g. `print(j)`, are colored properly. + +--- raw-blocky --- +// Test various raw parsing edge cases. +#let empty = ( + name: "empty", + input: ``, + text: "", +) + +#let backtick = ( + name: "backtick", + input: ``` ` ```, + text: "`", + block: false, +) + +#let lang-backtick = ( + name: "lang-backtick", + input: ```js ` ```, + lang: "js", + text: "`", + block: false, +) + +// The language tag stops on space +#let lang-space = ( + name: "lang-space", + input: ```js test ```, + lang: "js", + text: "test ", + block: false, +) + +// The language tag stops on newline +#let lang-newline = ( + name: "lang-newline", + input: ```js +test +```, + lang: "js", + text: "test", + block: true, +) + +// The first line and the last line are ignored +#let blocky = ( + name: "blocky", + input: { +``` +test +``` +}, + text: "test", + block: true, +) + +// A blocky raw should handle dedents +#let blocky-dedent = ( + name: "blocky-dedent", + input: { +``` + test + ``` + }, + text: "test", + block: true, +) + +// When there is content in the first line, it should exactly eat a whitespace char. +#let blocky-dedent-firstline = ( + name: "blocky-dedent-firstline", + input: ``` test + ```, + text: "test", + block: true, +) + +// When there is content in the first line, it should exactly eat a whitespace char. +#let blocky-dedent-firstline2 = ( + name: "blocky-dedent-firstline2", + input: ``` test +```, + text: "test", + block: true, +) + +// The first line is not affected by dedent, and the middle lines don't consider the whitespace prefix of the first line. +#let blocky-dedent-firstline3 = ( + name: "blocky-dedent-firstline3", + input: ``` test + test2 + ```, + text: "test\n test2", + block: true, +) + +// The first line is not affected by dedent, and the middle lines don't consider the whitespace prefix of the first line. +#let blocky-dedent-firstline4 = ( + name: "blocky-dedent-firstline4", + input: ``` test + test2 + ```, + text: " test\ntest2", + block: true, +) + +#let blocky-dedent-lastline = ( + name: "blocky-dedent-lastline", + input: ``` + test + ```, + text: " test", + block: true, +) + +#let blocky-dedent-lastline2 = ( + name: "blocky-dedent-lastline2", + input: ``` + test + ```, + text: "test", + block: true, +) + +#let blocky-tab = ( + name: "blocky-tab", + input: { +``` + test +``` +}, + text: "\ttest", + block: true, +) + +// This one is a bit problematic because there is a trailing tab below "test" +// which the editor constantly wants to remove. +#let blocky-tab-dedent = ( + name: "blocky-tab-dedent", + input: eval("```\n\ttest\n \n ```"), + text: "test\n ", + block: true, +) + +#let cases = ( + empty, + backtick, + lang-backtick, + lang-space, + lang-newline, + blocky, + blocky-dedent, + blocky-dedent-firstline, + blocky-dedent-firstline2, + blocky-dedent-firstline3, + blocky-dedent-lastline, + blocky-dedent-lastline2, + blocky-tab, + blocky-tab-dedent, +) + +#for c in cases { + assert.eq(c.text, c.input.text, message: "in point " + c.name + ", expect " + repr(c.text) + ", got " + repr(c.input.text) + "") + let block = c.at("block", default: false) + assert.eq(block, c.input.block, message: "in point " + c.name + ", expect " + repr(block) + ", got " + repr(c.input.block) + "") +} + +--- raw-line --- +#set page(width: 200pt) + +```rs +fn main() { + println!("Hello, world!"); +} +``` + +#show raw.line: it => { + box(stack( + dir: ltr, + box(width: 15pt)[#it.number], + it.body, + )) + linebreak() +} + +```rs +fn main() { + println!("Hello, world!"); +} +``` + +--- raw-line-alternating-fill --- +#set page(width: 200pt) +#show raw: it => stack(dir: ttb, ..it.lines) +#show raw.line: it => { + box( + width: 100%, + height: 1.75em, + inset: 0.25em, + fill: if calc.rem(it.number, 2) == 0 { + luma(90%) + } else { + white + }, + align(horizon, stack( + dir: ltr, + box(width: 15pt)[#it.number], + it.body, + )) + ) +} + +```typ +#show raw.line: block.with( + fill: luma(60%) +); + +Hello, world! + += A heading for good measure +``` + +--- raw-line-text-fill --- +#set page(width: 200pt) +#show raw.line: set text(fill: red) + +```py +import numpy as np + +def f(x): + return x**2 + +x = np.linspace(0, 10, 100) +y = f(x) + +print(x) +print(y) +``` + +--- raw-line-scripting --- + +// Test line extraction works. + +#show raw: code => { + for i in code.lines { + test(i.count, 10) + } + + test(code.lines.at(0).text, "import numpy as np") + test(code.lines.at(1).text, "") + test(code.lines.at(2).text, "def f(x):") + test(code.lines.at(3).text, " return x**2") + test(code.lines.at(4).text, "") + test(code.lines.at(5).text, "x = np.linspace(0, 10, 100)") + test(code.lines.at(6).text, "y = f(x)") + test(code.lines.at(7).text, "") + test(code.lines.at(8).text, "print(x)") + test(code.lines.at(9).text, "print(y)") + test(code.lines.at(10, default: none), none) +} + +```py +import numpy as np + +def f(x): + return x**2 + +x = np.linspace(0, 10, 100) +y = f(x) + +print(x) +print(y) +``` + +--- issue-3601-empty-raw --- +// Test that empty raw block with `typ` language doesn't cause a crash. +```typ +``` + +--- issue-3841-tabs-in-raw-type-code --- +// Tab chars were not rendered in raw blocks with lang: "typ(c)" +#raw("#if true {\n\tf()\t// typ\n}", lang: "typ") + +#raw("if true {\n\tf()\t// typc\n}", lang: "typc") + +```typ +#if true { + // tabs around f() + f() // typ +} +``` + +```typc +if true { + // tabs around f() + f() // typc +} +``` + +--- issue-2259-raw-color-overwrite --- +// Test that the color of a raw block is not overwritten +#show raw: set text(fill: blue) + +`Hello, World!` + +```rs +fn main() { + println!("Hello, World!"); +} +``` + +--- issue-3191-raw-indent-shrink --- +// Spaces in raw blocks should not be shrunk as it would mess up the indentation +// of code. +#set par(justify: true) + +#show raw.where(block: true): block.with( + fill: luma(240), + inset: 10pt, +) + +#block( + width: 60%, + ```py + for x in xs: + print("x=",x) + ``` +) + +--- issue-3191-raw-normal-paragraphs-still-shrink --- +// In normal paragraphs, spaces should still be shrunk. +// The first line here serves as a reference, while the second +// uses non-breaking spaces to create an overflowing line +// (which should shrink). +~~~~No shrinking here + +~~~~The~spaces~on~this~line~shrink + +--- raw-unclosed --- +// Unterminated. +// Error: 1-2:1 unclosed raw text +`endless diff --git a/tests/suite/text/shift.typ b/tests/suite/text/shift.typ new file mode 100644 index 00000000..090f6ee8 --- /dev/null +++ b/tests/suite/text/shift.typ @@ -0,0 +1,19 @@ +// Test sub- and superscipt shifts. + +--- sub-super --- +#table( + columns: 3, + [Typo.], [Fallb.], [Synth], + [x#super[1]], [x#super[5n]], [x#super[2 #box(square(size: 6pt))]], + [x#sub[1]], [x#sub[5n]], [x#sub[2 #box(square(size: 6pt))]], +) + +--- sub-super-non-typographic --- +#set super(typographic: false, baseline: -0.25em, size: 0.7em) +n#super[1], n#sub[2], ... n#super[N] + +--- super-underline --- +#set underline(stroke: 0.5pt, offset: 0.15em) +#underline[The claim#super[\[4\]]] has been disputed. \ +The claim#super[#underline[\[4\]]] has been disputed. \ +It really has been#super(box(text(baseline: 0pt, underline[\[4\]]))) \ diff --git a/tests/suite/text/smallcaps.typ b/tests/suite/text/smallcaps.typ new file mode 100644 index 00000000..6f977244 --- /dev/null +++ b/tests/suite/text/smallcaps.typ @@ -0,0 +1,3 @@ +--- smallcaps --- +// Test smallcaps. +#smallcaps[Smallcaps] diff --git a/tests/suite/text/smartquote.typ b/tests/suite/text/smartquote.typ new file mode 100644 index 00000000..28fcba5b --- /dev/null +++ b/tests/suite/text/smartquote.typ @@ -0,0 +1,122 @@ +--- smartquote --- +// LARGE +#set page(width: 250pt) + +// Test simple quotations in various languages. +#set text(lang: "en") +"The horse eats no cucumber salad" was the first sentence ever uttered on the 'telephone.' + +#set text(lang: "de") +"Das Pferd frisst keinen Gurkensalat" war der erste jemals am 'Fernsprecher' gesagte Satz. + +#set text(lang: "de", region: "CH") +"Das Pferd frisst keinen Gurkensalat" war der erste jemals am 'Fernsprecher' gesagte Satz. + +#set text(lang: "es", region: none) +"El caballo no come ensalada de pepino" fue la primera frase pronunciada por 'teléfono'. + +#set text(lang: "es", region: "MX") +"El caballo no come ensalada de pepino" fue la primera frase pronunciada por 'teléfono'. + +#set text(lang: "fr", region: none) +"Le cheval ne mange pas de salade de concombres" est la première phrase jamais prononcée au 'téléphone'. + +#set text(lang: "fi") +"Hevonen ei syö kurkkusalaattia" oli ensimmäinen koskaan 'puhelimessa' lausuttu lause. + +#set text(lang: "gr") +"Το άλογο δεν τρώει αγγουροσαλάτα" ήταν η πρώτη πρόταση που ειπώθηκε στο 'τηλέφωνο'. + +#set text(lang: "he") +"הסוס לא אוכל סלט מלפפונים" היה המשפט ההראשון שנאמר ב 'טלפון'. + +#set text(lang: "ro") +"Calul nu mănâncă salată de castraveți" a fost prima propoziție rostită vreodată la 'telefon'. + +#set text(lang: "ru") +"Лошадь не ест салат из огурцов" - это была первая фраза, сказанная по 'телефону'. + +--- smartquote-empty --- +// Test single pair of quotes. +"" + +--- smartquote-apostrophe --- +// Test sentences with numbers and apostrophes. +The 5'11" 'quick' brown fox jumps over the "lazy" dog's ear. + +He said "I'm a big fella." + +--- smartquote-escape --- +// Test escape sequences. +The 5\'11\" 'quick\' brown fox jumps over the \"lazy" dog\'s ear. + +--- smartquote-disable --- +// Test turning smart quotes off. +He's told some books contain questionable "example text". + +#set smartquote(enabled: false) +He's told some books contain questionable "example text". + +--- smartquote-disabled-temporarily --- +// Test changing properties within text. +"She suddenly started speaking french: #text(lang: "fr")['Je suis une banane.']" Roman told me. + +Some people's thought on this would be #[#set smartquote(enabled: false); "strange."] + +--- smartquote-nesting --- +// Test nested double and single quotes. +"'test statement'" \ +"'test' statement" \ +"statement 'test'" + +--- smartquote-custom --- +// Use language quotes for missing keys, allow partial reset +#set smartquote(quotes: "«»") +"Double and 'Single' Quotes" + +#set smartquote(quotes: (double: auto, single: "«»")) +"Double and 'Single' Quotes" + +--- smartquote-custom-complex --- +// Allow 2 graphemes +#set smartquote(quotes: "a\u{0301}a\u{0301}") +"Double and 'Single' Quotes" + +#set smartquote(quotes: (single: "a\u{0301}a\u{0301}")) +"Double and 'Single' Quotes" + +--- smartquote-custom-bad-string --- +// Error: 25-28 expected 2 characters, found 1 character +#set smartquote(quotes: "'") + +--- smartquote-custom-bad-array --- +// Error: 25-35 expected 2 quotes, found 4 quotes +#set smartquote(quotes: ("'",) * 4) + +--- smartquote-custom-bad-dict --- +// Error: 25-45 expected 2 quotes, found 4 quotes +#set smartquote(quotes: (single: ("'",) * 4)) + +--- issue-3662-pdf-smartquotes --- +// Smart quotes were not appearing in the PDF outline, because they didn't +// implement `PlainText`. += It's "Unnormal Heading" += It’s “Normal Heading” + +#set smartquote(enabled: false) += It's "Unnormal Heading" += It's 'single quotes' += It’s “Normal Heading” + +--- issue-1041-smartquotes-in-outline --- +#set page(width: 15em) +#outline() + += "This" "is" "a" "test" + +--- issue-1540-smartquotes-across-newlines --- +// Test that smart quotes are inferred correctly across newlines. +"test"#linebreak()"test" + +"test"\ +"test" diff --git a/tests/suite/text/space.typ b/tests/suite/text/space.typ new file mode 100644 index 00000000..97541e38 --- /dev/null +++ b/tests/suite/text/space.typ @@ -0,0 +1,60 @@ +// Test whitespace handling. + +--- space-collapsing --- +// Spacing around code constructs. +A#let x = 1;B #test(x, 1) \ +C #let x = 2;D #test(x, 2) \ +E#if true [F]G \ +H #if true{"I"} J \ +K #if true [L] else []M \ +#let c = true; N#while c [#(c = false)O] P \ +#let c = true; Q #while c { c = false; "R" } S \ +T#for _ in (none,) {"U"}V +#let foo = "A" ; \ +#foo;B \ +#foo; B \ +#foo ;B + +--- space-collapsing-comments --- +// Test spacing with comments. +A/**/B/**/C \ +A /**/ B/**/C \ +A /**/B/**/ C + +--- space-collapsing-with-h --- +// Test spacing collapsing before spacing. +#set align(right) +A #h(0pt) B #h(0pt) \ +A B \ +A #h(-1fr) B + +--- text-font-just-a-space --- +// Test that a run consisting only of whitespace isn't trimmed. +A#text(font: "IBM Plex Serif")[ ]B + +--- text-font-change-after-space --- +// Test font change after space. +Left #text(font: "IBM Plex Serif")[Right]. + +--- space-collapsing-linebreaks --- +// Test that linebreak consumed surrounding spaces. +#align(center)[A \ B \ C] + +--- space-collapsing-stringy-linebreak --- +// Test that space at start of non-backslash-linebreak line isn't trimmed. +A#"\n" B + +--- space-trailing-linebreak --- +// Test that trailing space does not force a line break. +LLLLLLLLLLLLLLLLLL R _L_ + +--- space-ideographic-kept --- +// Test that ideographic spaces are preserved. +#set text(lang: "ja", font: "Noto Serif CJK JP") + +だろうか? 何のために! 私は、 + +--- space-thin-kept --- +// Test that thin spaces are preserved. +| | U+0020 regular space \ +| | U+2009 thin space diff --git a/tests/suite/visualize/circle.typ b/tests/suite/visualize/circle.typ new file mode 100644 index 00000000..43459eb5 --- /dev/null +++ b/tests/suite/visualize/circle.typ @@ -0,0 +1,69 @@ +// Test the `circle` function. + +--- circle --- +// Default circle. +#box(circle()) +#box(circle[Hey]) + +--- circle-auto-sizing --- +// Test auto sizing. +#set circle(inset: 0pt) + +Auto-sized circle. +#circle(fill: rgb("eb5278"), stroke: 2pt + black, + align(center + horizon)[But, soft!] +) + +Center-aligned rect in auto-sized circle. +#circle(fill: forest, stroke: conifer, + align(center + horizon, + rect(fill: conifer, inset: 5pt)[But, soft!] + ) +) + +Rect in auto-sized circle. +#circle(fill: forest, + rect(fill: conifer, stroke: white, inset: 4pt)[ + #set text(8pt) + But, soft! what light through yonder window breaks? + ] +) + +Expanded by height. +#circle(stroke: black, align(center)[A \ B \ C]) + +--- circle-directly-in-rect --- +// Ensure circle directly in rect works. +#rect(width: 40pt, height: 30pt, fill: forest, + circle(fill: conifer)) + +--- circle-relative-sizing --- +// Test relative sizing. +#set text(fill: white) +#show: rect.with(width: 100pt, height: 50pt, inset: 0pt, fill: rgb("aaa")) +#set align(center + horizon) +#stack( + dir: ltr, + spacing: 1fr, + 1fr, + circle(radius: 10pt, fill: eastern, [A]), // D=20pt + circle(height: 60%, fill: eastern, [B]), // D=30pt + circle(width: 20% + 20pt, fill: eastern, [C]), // D=40pt + 1fr, +) + +--- circle-radius-width-and-height --- +// Radius wins over width and height. +// Error: 23-34 unexpected argument: width +#circle(radius: 10pt, width: 50pt, height: 100pt, fill: eastern) + +--- circle-sizing-options --- +// Test different ways of sizing. +#set page(width: 120pt, height: 40pt) +#stack( + dir: ltr, + spacing: 2pt, + circle(radius: 5pt), + circle(width: 10%), + circle(height: 50%), +) diff --git a/tests/suite/visualize/color.typ b/tests/suite/visualize/color.typ new file mode 100644 index 00000000..6cf887a4 --- /dev/null +++ b/tests/suite/visualize/color.typ @@ -0,0 +1,331 @@ +// Test color modification methods. + +--- color-mix --- +// Compare both ways. +#test-repr(rgb(0%, 30.2%, 70.2%), rgb("004db3")) + +// Alpha channel. +#test(rgb(255, 0, 0, 50%), rgb("ff000080")) + +// Test color modification methods. +#test(rgb(25, 35, 45).lighten(10%), rgb(48, 57, 66)) +#test(rgb(40, 30, 20).darken(10%), rgb(36, 27, 18)) +#test(rgb("#133337").negate(space: rgb), rgb(236, 204, 200)) +#test(white.lighten(100%), white) + +// Color mixing, in Oklab space by default. +#test(rgb(color.mix(rgb("#ff0000"), rgb("#00ff00"))), rgb("#d0a800")) +#test(rgb(color.mix(rgb("#ff0000"), rgb("#00ff00"), space: oklab)), rgb("#d0a800")) +#test(rgb(color.mix(rgb("#ff0000"), rgb("#00ff00"), space: rgb)), rgb("#808000")) + +#test(rgb(color.mix(red, green, blue)), rgb("#909282")) +#test(rgb(color.mix(red, blue, green)), rgb("#909282")) +#test(rgb(color.mix(blue, red, green)), rgb("#909282")) + +// Mix with weights. +#test(rgb(color.mix((red, 50%), (green, 50%))), rgb("#c0983b")) +#test(rgb(color.mix((red, 0.5), (green, 0.5))), rgb("#c0983b")) +#test(rgb(color.mix((red, 5), (green, 5))), rgb("#c0983b")) +#test(rgb(color.mix((green, 5), (white, 0), (red, 5))), rgb("#c0983b")) +#test(color.mix((rgb("#aaff00"), 25%), (rgb("#aa00ff"), 75%), space: rgb), rgb("#aa40bf")) +#test(color.mix((rgb("#aaff00"), 50%), (rgb("#aa00ff"), 50%), space: rgb), rgb("#aa8080")) +#test(color.mix((rgb("#aaff00"), 75%), (rgb("#aa00ff"), 25%), space: rgb), rgb("#aabf40")) + +// Mix in hue-based space. +#test(rgb(color.mix(red, blue, space: color.hsl)), rgb("#c408ff")) +#test(rgb(color.mix((red, 50%), (blue, 100%), space: color.hsl)), rgb("#5100f8")) +// Error: 6-51 cannot mix more than two colors in a hue-based space +#rgb(color.mix(red, blue, white, space: color.hsl)) + +--- color-conversion --- +// Test color conversion method kinds +#test(rgb(rgb(10, 20, 30)).space(), rgb) +#test(color.linear-rgb(rgb(10, 20, 30)).space(), color.linear-rgb) +#test(oklab(rgb(10, 20, 30)).space(), oklab) +#test(oklch(rgb(10, 20, 30)).space(), oklch) +#test(color.hsl(rgb(10, 20, 30)).space(), color.hsl) +#test(color.hsv(rgb(10, 20, 30)).space(), color.hsv) +#test(cmyk(rgb(10, 20, 30)).space(), cmyk) +#test(luma(rgb(10, 20, 30)).space(), luma) + +#test(rgb(color.linear-rgb(10, 20, 30)).space(), rgb) +#test(color.linear-rgb(color.linear-rgb(10, 20, 30)).space(), color.linear-rgb) +#test(oklab(color.linear-rgb(10, 20, 30)).space(), oklab) +#test(oklch(color.linear-rgb(10, 20, 30)).space(), oklch) +#test(color.hsl(color.linear-rgb(10, 20, 30)).space(), color.hsl) +#test(color.hsv(color.linear-rgb(10, 20, 30)).space(), color.hsv) +#test(cmyk(color.linear-rgb(10, 20, 30)).space(), cmyk) +#test(luma(color.linear-rgb(10, 20, 30)).space(), luma) + +#test(rgb(oklab(10%, 20%, 30%)).space(), rgb) +#test(color.linear-rgb(oklab(10%, 20%, 30%)).space(), color.linear-rgb) +#test(oklab(oklab(10%, 20%, 30%)).space(), oklab) +#test(oklch(oklab(10%, 20%, 30%)).space(), oklch) +#test(color.hsl(oklab(10%, 20%, 30%)).space(), color.hsl) +#test(color.hsv(oklab(10%, 20%, 30%)).space(), color.hsv) +#test(cmyk(oklab(10%, 20%, 30%)).space(), cmyk) +#test(luma(oklab(10%, 20%, 30%)).space(), luma) + +#test(rgb(oklch(60%, 40%, 0deg)).space(), rgb) +#test(color.linear-rgb(oklch(60%, 40%, 0deg)).space(), color.linear-rgb) +#test(oklab(oklch(60%, 40%, 0deg)).space(), oklab) +#test(oklch(oklch(60%, 40%, 0deg)).space(), oklch) +#test(color.hsl(oklch(60%, 40%, 0deg)).space(), color.hsl) +#test(color.hsv(oklch(60%, 40%, 0deg)).space(), color.hsv) +#test(cmyk(oklch(60%, 40%, 0deg)).space(), cmyk) +#test(luma(oklch(60%, 40%, 0deg)).space(), luma) + +#test(rgb(color.hsl(10deg, 20%, 30%)).space(), rgb) +#test(color.linear-rgb(color.hsl(10deg, 20%, 30%)).space(), color.linear-rgb) +#test(oklab(color.hsl(10deg, 20%, 30%)).space(), oklab) +#test(oklch(color.hsl(10deg, 20%, 30%)).space(), oklch) +#test(color.hsl(color.hsl(10deg, 20%, 30%)).space(), color.hsl) +#test(color.hsv(color.hsl(10deg, 20%, 30%)).space(), color.hsv) +#test(cmyk(color.hsl(10deg, 20%, 30%)).space(), cmyk) +#test(luma(color.hsl(10deg, 20%, 30%)).space(), luma) + +#test(rgb(color.hsv(10deg, 20%, 30%)).space(), rgb) +#test(color.linear-rgb(color.hsv(10deg, 20%, 30%)).space(), color.linear-rgb) +#test(oklab(color.hsv(10deg, 20%, 30%)).space(), oklab) +#test(oklch(color.hsv(10deg, 20%, 30%)).space(), oklch) +#test(color.hsl(color.hsv(10deg, 20%, 30%)).space(), color.hsl) +#test(color.hsv(color.hsv(10deg, 20%, 30%)).space(), color.hsv) +#test(cmyk(color.hsv(10deg, 20%, 30%)).space(), cmyk) +#test(luma(color.hsv(10deg, 20%, 30%)).space(), luma) + +#test(rgb(cmyk(10%, 20%, 30%, 40%)).space(), rgb) +#test(color.linear-rgb(cmyk(10%, 20%, 30%, 40%)).space(), color.linear-rgb) +#test(oklab(cmyk(10%, 20%, 30%, 40%)).space(), oklab) +#test(oklch(cmyk(10%, 20%, 30%, 40%)).space(), oklch) +#test(color.hsl(cmyk(10%, 20%, 30%, 40%)).space(), color.hsl) +#test(color.hsv(cmyk(10%, 20%, 30%, 40%)).space(), color.hsv) +#test(cmyk(cmyk(10%, 20%, 30%, 40%)).space(), cmyk) +#test(luma(cmyk(10%, 20%, 30%, 40%)).space(), luma) + +#test(rgb(luma(10%)).space(), rgb) +#test(color.linear-rgb(luma(10%)).space(), color.linear-rgb) +#test(oklab(luma(10%)).space(), oklab) +#test(oklch(luma(10%)).space(), oklch) +#test(color.hsl(luma(10%)).space(), color.hsl) +#test(color.hsv(luma(10%)).space(), color.hsv) +#test(cmyk(luma(10%)).space(), cmyk) +#test(luma(luma(10%)).space(), luma) + +#test(rgb(1, 2, 3).to-hex(), "#010203") +#test(rgb(1, 2, 3, 4).to-hex(), "#01020304") +#test(luma(40).to-hex(), "#282828") +#test-repr(cmyk(4%, 5%, 6%, 7%).to-hex(), "#e0dcda") +#test-repr(rgb(cmyk(4%, 5%, 6%, 7%)), rgb(87.84%, 86.27%, 85.49%, 100%)) +#test-repr(rgb(luma(40%)), rgb(40%, 40%, 40%)) +#test-repr(cmyk(luma(40)), cmyk(11.76%, 10.67%, 10.51%, 14.12%)) +#test-repr(cmyk(rgb(1, 2, 3)), cmyk(66.67%, 33.33%, 0%, 98.82%)) +#test-repr(luma(rgb(1, 2, 3)), luma(0.73%)) +#test-repr(color.hsl(luma(40)), color.hsl(0deg, 0%, 15.69%)) +#test-repr(color.hsv(luma(40)), color.hsv(0deg, 0%, 15.69%)) +#test-repr(color.linear-rgb(luma(40)), color.linear-rgb(2.12%, 2.12%, 2.12%)) +#test-repr(color.linear-rgb(rgb(1, 2, 3)), color.linear-rgb(0.03%, 0.06%, 0.09%)) +#test-repr(color.hsl(rgb(1, 2, 3)), color.hsl(-150deg, 50%, 0.78%)) +#test-repr(color.hsv(rgb(1, 2, 3)), color.hsv(-150deg, 66.67%, 1.18%)) +#test-repr(oklab(luma(40)), oklab(27.68%, 0.0, 0.0, 100%)) +#test-repr(oklab(rgb(1, 2, 3)), oklab(8.23%, -0.004, -0.007, 100%)) +#test-repr(oklch(oklab(40%, 0.2, 0.2)), oklch(40%, 0.283, 45deg, 100%)) +#test-repr(oklch(luma(40)), oklch(27.68%, 0.0, 72.49deg, 100%)) +#test-repr(oklch(rgb(1, 2, 3)), oklch(8.23%, 0.008, 240.75deg, 100%)) + +--- color-spaces --- +// The the different color spaces +#let col = rgb(50%, 64%, 16%) +#box(square(size: 9pt, fill: col)) +#box(square(size: 9pt, fill: rgb(col))) +#box(square(size: 9pt, fill: oklab(col))) +#box(square(size: 9pt, fill: oklch(col))) +#box(square(size: 9pt, fill: luma(col))) +#box(square(size: 9pt, fill: cmyk(col))) +#box(square(size: 9pt, fill: color.linear-rgb(col))) +#box(square(size: 9pt, fill: color.hsl(col))) +#box(square(size: 9pt, fill: color.hsv(col))) + +--- color-space --- +// Test color kind method. +#test(rgb(1, 2, 3, 4).space(), rgb) +#test(cmyk(4%, 5%, 6%, 7%).space(), cmyk) +#test(luma(40).space(), luma) +#test(rgb(1, 2, 3, 4).space() != luma, true) + +--- color-components --- +// Test color '.components()' without conversions + +#let test-components(col, ref, has-alpha: true) = { + // Perform an approximate scalar comparison. + let are-equal((a, b)) = { + let to-float(x) = if type(x) == angle { x.rad() } else { float(x) } + let epsilon = 1e-4 // The maximum error between both numbers + assert.eq(type(a), type(b)) + calc.abs(to-float(a) - to-float(b)) < epsilon + } + + let ref-without-alpha = if has-alpha { ref.slice(0, -1) } else { ref } + assert.eq(col.components().len(), ref.len()) + assert(col.components().zip(ref).all(are-equal)) + assert(col.components(alpha: false).zip(ref-without-alpha).all(are-equal)) +} +#test-components(rgb(1, 2, 3, 4), (0.39%, 0.78%, 1.18%, 1.57%)) +#test-components(luma(40), (15.69%, 100%)) +#test-components(luma(40, 50%), (15.69%, 50%)) +#test-components(cmyk(4%, 5%, 6%, 7%), (4%, 5%, 6%, 7%), has-alpha: false) +#test-components(oklab(10%, 0.2, 0.4), (10%, 0.2, 0.4, 100%)) +#test-components(oklch(10%, 0.2, 90deg), (10%, 0.2, 90deg, 100%)) +#test-components(oklab(10%, 50%, 200%), (10%, 0.2, 0.8, 100%)) +#test-components(oklch(10%, 50%, 90deg), (10%, 0.2, 90deg, 100%)) +#test-components(color.linear-rgb(10%, 20%, 30%), (10%, 20%, 30%, 100%)) +#test-components(color.hsv(10deg, 20%, 30%), (10deg, 20%, 30%, 100%)) +#test-components(color.hsl(10deg, 20%, 30%), (10deg, 20%, 30%, 100%)) + +--- color-luma --- +// Test gray color conversion. +#stack(dir: ltr, rect(fill: luma(0)), rect(fill: luma(80%))) + +--- color-rgb-out-of-range --- +// Error for values that are out of range. +// Error: 11-14 number must be between 0 and 255 +#test(rgb(-30, 15, 50)) + +--- color-rgb-bad-string --- +// Error: 6-11 color string contains non-hexadecimal letters +#rgb("lol") + +--- color-rgb-missing-argument-red --- +// Error: 2-7 missing argument: red component +#rgb() + +--- color-rgb-missing-argument-blue --- +// Error: 2-11 missing argument: blue component +#rgb(0, 1) + +--- color-rgb-bad-type --- +// Error: 21-26 expected integer or ratio, found boolean +#rgb(10%, 20%, 30%, false) + +--- color-luma-unexpected-argument --- +// Error: 10-20 unexpected argument: key +#luma(1, key: "val") + +--- color-mix-bad-amount-type --- +// Error: 12-24 expected float or ratio, found string +// Error: 26-39 expected float or ratio, found string +#color.mix((red, "yes"), (green, "no"), (green, 10%)) + +--- color-mix-bad-value --- +// Error: 12-23 expected a color or color-weight pair +#color.mix((red, 1, 2)) + +--- color-mix-bad-space-type --- +// Error: 31-38 expected `rgb`, `luma`, `cmyk`, `oklab`, `oklch`, `color.linear-rgb`, `color.hsl`, or `color.hsv`, found string +#color.mix(red, green, space: "cyber") + +--- color-mix-bad-space-value-1 --- +// Error: 31-36 expected `rgb`, `luma`, `cmyk`, `oklab`, `oklch`, `color.linear-rgb`, `color.hsl`, or `color.hsv` +#color.mix(red, green, space: image) + +--- color-mix-bad-space-value-2 --- +// Error: 31-41 expected `rgb`, `luma`, `cmyk`, `oklab`, `oklch`, `color.linear-rgb`, `color.hsl`, or `color.hsv` +#color.mix(red, green, space: calc.round) + +--- color-cmyk-ops --- +// Test CMYK color conversion. +#let c = cmyk(50%, 64%, 16%, 17%) +#stack( + dir: ltr, + spacing: 1fr, + rect(width: 1cm, fill: cmyk(69%, 11%, 69%, 41%)), + rect(width: 1cm, fill: c), + rect(width: 1cm, fill: c.negate(space: cmyk)), +) + +#for x in range(0, 11) { + box(square(size: 9pt, fill: c.lighten(x * 10%))) +} +#for x in range(0, 11) { + box(square(size: 9pt, fill: c.darken(x * 10%))) +} + +--- color-outside-srgb-gamut --- +// Colors outside the sRGB gamut. +#box(square(size: 9pt, fill: oklab(90%, -0.2, -0.1))) +#box(square(size: 9pt, fill: oklch(50%, 0.5, 0deg))) + +--- color-rotate-hue --- +// Test hue rotation +#let col = rgb(50%, 64%, 16%) + +// Oklch +#for x in range(0, 11) { + box(square(size: 9pt, fill: rgb(col).rotate(x * 36deg))) +} + +// HSL +#for x in range(0, 11) { + box(square(size: 9pt, fill: rgb(col).rotate(x * 36deg, space: color.hsl))) +} + +// HSV +#for x in range(0, 11) { + box(square(size: 9pt, fill: rgb(col).rotate(x * 36deg, space: color.hsv))) +} + +--- color-saturation --- +// Test saturation +#let col = color.hsl(180deg, 0%, 50%) +#for x in range(0, 11) { + box(square(size: 9pt, fill: col.saturate(x * 10%))) +} + +#let col = color.hsl(180deg, 100%, 50%) +#for x in range(0, 11) { + box(square(size: 9pt, fill: col.desaturate(x * 10%))) +} + +#let col = color.hsv(180deg, 0%, 50%) +#for x in range(0, 11) { + box(square(size: 9pt, fill: col.saturate(x * 10%))) +} + +#let col = color.hsv(180deg, 100%, 50%) +#for x in range(0, 11) { + box(square(size: 9pt, fill: col.desaturate(x * 10%))) +} + +--- color-luma-ops --- +// Test gray color modification. +#test-repr(luma(20%).lighten(50%), luma(60%)) +#test-repr(luma(80%).darken(20%), luma(64%)) +#test-repr(luma(80%).negate(space: luma), luma(20%)) + +--- color-transparentize --- +// Test alpha modification. +#test-repr(luma(100%, 100%).transparentize(50%), luma(100%, 50%)) +#test-repr(luma(100%, 100%).transparentize(75%), luma(100%, 25%)) +#test-repr(luma(100%, 50%).transparentize(50%), luma(100%, 25%)) +#test-repr(luma(100%, 10%).transparentize(250%), luma(100%, 0%)) +#test-repr(luma(100%, 40%).transparentize(-50%), luma(100%, 70%)) +#test-repr(luma(100%, 0%).transparentize(-100%), luma(100%, 100%)) + +--- color-opacify --- +#test-repr(luma(100%, 50%).opacify(50%), luma(100%, 75%)) +#test-repr(luma(100%, 20%).opacify(100%), luma(100%, 100%)) +#test-repr(luma(100%, 100%).opacify(250%), luma(100%, 100%)) +#test-repr(luma(100%, 50%).opacify(-50%), luma(100%, 25%)) +#test-repr(luma(100%, 0%).opacify(0%), luma(100%, 0%)) + +--- repr-color --- +// Colors +#set page(width: 400pt) +#set text(0.8em) +#blue \ +#color.linear-rgb(blue) \ +#oklab(blue) \ +#oklch(blue) \ +#cmyk(blue) \ +#color.hsl(blue) \ +#color.hsv(blue) \ +#luma(blue) diff --git a/tests/suite/visualize/ellipse.typ b/tests/suite/visualize/ellipse.typ new file mode 100644 index 00000000..970a795e --- /dev/null +++ b/tests/suite/visualize/ellipse.typ @@ -0,0 +1,31 @@ +// Test the `ellipse` function. + +--- ellipse --- +// Default ellipse. +#ellipse() + +--- ellipse-auto-sizing --- +#set rect(inset: 0pt) +#set ellipse(inset: 0pt) + +Rect in ellipse in fixed rect. +#rect(width: 3cm, height: 2cm, fill: rgb("2a631a"), + ellipse(fill: forest, width: 100%, height: 100%, + rect(fill: conifer, width: 100%, height: 100%, + align(center + horizon)[ + Stuff inside an ellipse! + ] + ) + ) +) + +Auto-sized ellipse. +#ellipse(fill: conifer, stroke: 3pt + forest, inset: 3pt)[ + #set text(8pt) + But, soft! what light through yonder window breaks? +] + + +An inline +#box(ellipse(width: 8pt, height: 6pt, outset: (top: 3pt, rest: 5.5pt))) +ellipse. diff --git a/tests/suite/visualize/gradient.typ b/tests/suite/visualize/gradient.typ new file mode 100644 index 00000000..1ee5489a --- /dev/null +++ b/tests/suite/visualize/gradient.typ @@ -0,0 +1,631 @@ +--- gradient-linear-angled --- +// Test gradients with direction. +#set page(width: 90pt) +#grid( + gutter: 3pt, + columns: 4, + ..range(0, 360, step: 15).map(i => box( + height: 15pt, + width: 15pt, + fill: gradient.linear(angle: i * 1deg, (red, 0%), (blue, 100%)), + )) +) + + +--- gradient-linear-oklab --- +// The tests below test whether hue rotation works correctly. +// Here we test in Oklab space for reference. +#set page( + width: 100pt, + height: 30pt, + fill: gradient.linear(red, purple, space: oklab) +) + +--- gradient-linear-oklch --- +// Test in OkLCH space. +#set page( + width: 100pt, + height: 30pt, + fill: gradient.linear(red, purple, space: oklch) +) + +--- gradient-linear-hsv --- +// Test in HSV space. +#set page( + width: 100pt, + height: 30pt, + fill: gradient.linear(red, purple, space: color.hsv) +) + +--- gradient-linear-hsl --- +// Test in HSL space. +#set page( + width: 100pt, + height: 30pt, + fill: gradient.linear(red, purple, space: color.hsl) +) + + +--- gradient-linear-relative-parent --- +// The image should look as if there is a single gradient that is being used for +// both the page and the rectangles. +#let grad = gradient.linear(red, blue, green, purple, relative: "parent"); +#let my-rect = rect(width: 50%, height: 50%, fill: grad) +#set page( + height: 50pt, + width: 50pt, + margin: 2.5pt, + fill: grad, + background: place(top + left, my-rect), +) +#place(top + right, my-rect) +#place(bottom + center, rotate(45deg, my-rect)) + +--- gradient-linear-relative-self --- +// The image should look as if there are multiple gradients, one for each +// rectangle. +#let grad = gradient.linear(red, blue, green, purple, relative: "self"); +#let my-rect = rect(width: 50%, height: 50%, fill: grad) +#set page( + height: 50pt, + width: 50pt, + margin: 2.5pt, + fill: grad, + background: place(top + left, my-rect), +) +#place(top + right, my-rect) +#place(bottom + center, rotate(45deg, my-rect)) + +--- gradient-linear-repeat-and-mirror-1 --- +// Test repeated gradients. +#rect( + height: 40pt, + width: 100%, + fill: gradient.linear(..color.map.inferno).repeat(2, mirror: true) +) + +--- gradient-linear-repeat-and-mirror-2 --- +#rect( + height: 40pt, + width: 100%, + fill: gradient.linear(..color.map.rainbow).repeat(2, mirror: true), +) + +--- gradient-linear-repeat-and-mirror-3 --- +#rect( + height: 40pt, + width: 100%, + fill: gradient.linear(..color.map.rainbow).repeat(5, mirror: true) +) + +--- gradient-linear-sharp-and-repeat --- +#rect( + height: 40pt, + width: 100%, + fill: gradient.linear(..color.map.rainbow).sharp(10).repeat(5, mirror: false) +) + +--- gradient-linear-sharp-repeat-and-mirror --- +#rect( + height: 40pt, + width: 100%, + fill: gradient.linear(..color.map.rainbow).sharp(10).repeat(5, mirror: true) +) + +--- gradient-linear-sharp --- +#square( + size: 100pt, + fill: gradient.linear(..color.map.rainbow, space: color.hsl).sharp(10), +) +#square( + size: 100pt, + fill: gradient.radial(..color.map.rainbow, space: color.hsl).sharp(10), +) +#square( + size: 100pt, + fill: gradient.conic(..color.map.rainbow, space: color.hsl).sharp(10), +) + +--- gradient-linear-sharp-and-smooth --- +#square( + size: 100pt, + fill: gradient.linear(..color.map.rainbow, space: color.hsl).sharp(10, smoothness: 40%), +) +#square( + size: 100pt, + fill: gradient.radial(..color.map.rainbow, space: color.hsl).sharp(10, smoothness: 40%), +) +#square( + size: 100pt, + fill: gradient.conic(..color.map.rainbow, space: color.hsl).sharp(10, smoothness: 40%), +) + +--- gradient-linear-stroke --- +#align(center + top, square(size: 50pt, fill: black, stroke: 5pt + gradient.linear(red, blue))) + +--- gradient-fill-and-stroke --- +#align( + center + bottom, + square( + size: 50pt, + fill: gradient.radial(red, blue, radius: 70.7%, focal-center: (10%, 10%)), + stroke: 10pt + gradient.radial(red, blue, radius: 70.7%, focal-center: (10%, 10%)) + ) +) + +--- gradient-linear-line --- +// Test gradient on lines +#set page(width: 100pt, height: 100pt) +#line(length: 100%, stroke: 1pt + gradient.linear(red, blue)) +#line(length: 100%, angle: 10deg, stroke: 1pt + gradient.linear(red, blue)) +#line(length: 100%, angle: 10deg, stroke: 1pt + gradient.linear(red, blue, relative: "parent")) + +--- gradient-radial-hsl --- +#square( + size: 100pt, + fill: gradient.radial(..color.map.rainbow, space: color.hsl), +) + +--- gradient-radial-center --- +#grid( + columns: 2, + square( + size: 50pt, + fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (0%, 0%)), + ), + square( + size: 50pt, + fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (0%, 100%)), + ), + square( + size: 50pt, + fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (100%, 0%)), + ), + square( + size: 50pt, + fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (100%, 100%)), + ), +) + +--- gradient-radial-radius --- +#square( + size: 50pt, + fill: gradient.radial(..color.map.rainbow, space: color.hsl, radius: 10%), +) +#square( + size: 50pt, + fill: gradient.radial(..color.map.rainbow, space: color.hsl, radius: 72%), +) + +--- gradient-radial-focal-center-and-radius --- +#circle( + radius: 25pt, + fill: gradient.radial(white, rgb("#8fbc8f"), focal-center: (35%, 35%), focal-radius: 5%), +) +#circle( + radius: 25pt, + fill: gradient.radial(white, rgb("#8fbc8f"), focal-center: (75%, 35%), focal-radius: 5%), +) + +--- gradient-radial-relative-parent --- +// The image should look as if there is a single gradient that is being used for +// both the page and the rectangles. +#let grad = gradient.radial(red, blue, green, purple, relative: "parent"); +#let my-rect = rect(width: 50%, height: 50%, fill: grad) +#set page( + height: 50pt, + width: 50pt, + margin: 2.5pt, + fill: grad, + background: place(top + left, my-rect), +) +#place(top + right, my-rect) +#place(bottom + center, rotate(45deg, my-rect)) + +--- gradient-radial-relative-self --- +// The image should look as if there are multiple gradients, one for each +// rectangle. +#let grad = gradient.radial(red, blue, green, purple, relative: "self"); +#let my-rect = rect(width: 50%, height: 50%, fill: grad) +#set page( + height: 50pt, + width: 50pt, + margin: 2.5pt, + fill: grad, + background: place(top + left, my-rect), +) +#place(top + right, my-rect) +#place(bottom + center, rotate(45deg, my-rect)) + +--- gradient-radial-text --- +// Test that gradient fills on text. +// The solid bar gradients are used to make sure that all transforms are +// correct: if you can see the text through the bar, then the gradient is +// misaligned to its reference container. +#set page(width: 200pt, height: auto, margin: 10pt) +#set par(justify: true) +#set text(fill: gradient.radial(red, blue)) +#lorem(30) + +--- gradient-conic --- +#square( + size: 50pt, + fill: gradient.conic(..color.map.rainbow, space: color.hsv), +) + +--- gradient-conic-center-shifted-1 --- +#square( + size: 50pt, + fill: gradient.conic(..color.map.rainbow, space: color.hsv, center: (10%, 10%)), +) + +--- gradient-conic-center-shifted-2 --- +#square( + size: 50pt, + fill: gradient.conic(..color.map.rainbow, space: color.hsv, center: (90%, 90%)), +) + +--- gradient-conic-angled --- +#square( + size: 50pt, + fill: gradient.conic(..color.map.rainbow, space: color.hsv, angle: 90deg), +) + +--- gradient-conic-oklab --- +// Test in Oklab space for reference. +#set page( + width: 100pt, + height: 100pt, + fill: gradient.conic(red, purple, space: oklab) +) + +--- gradient-conic-oklch --- +// Test in OkLCH space. +#set page( + width: 100pt, + height: 100pt, + fill: gradient.conic(red, purple, space: oklch) +) + +--- gradient-conic-hsv --- +// Test in HSV space. +#set page( + width: 100pt, + height: 100pt, + fill: gradient.conic(red, purple, space: color.hsv) +) + +--- gradient-conic-hsl --- +// Test in HSL space. +#set page( + width: 100pt, + height: 100pt, + fill: gradient.conic(red, purple, space: color.hsl) +) + +--- gradient-conic-relative-parent --- +// The image should look as if there is a single gradient that is being used for +// both the page and the rectangles. +#let grad = gradient.conic(red, blue, green, purple, relative: "parent"); +#let my-rect = rect(width: 50%, height: 50%, fill: grad) +#set page( + height: 50pt, + width: 50pt, + margin: 2.5pt, + fill: grad, + background: place(top + left, my-rect), +) +#place(top + right, my-rect) +#place(bottom + center, rotate(45deg, my-rect)) + +--- gradient-conic-relative-self --- +// The image should look as if there are multiple gradients, one for each +// rectangle. +#let grad = gradient.conic(red, blue, green, purple, relative: "self"); +#let my-rect = rect(width: 50%, height: 50%, fill: grad) +#set page( + height: 50pt, + width: 50pt, + margin: 2.5pt, + fill: grad, + background: place(top + left, my-rect), +) +#place(top + right, my-rect) +#place(bottom + center, rotate(45deg, my-rect)) + +--- gradient-conic-stroke --- +#align( + center + bottom, + square( + size: 50pt, + fill: black, + stroke: 10pt + gradient.conic(red, blue) + ) +) + +--- gradient-conic-text --- +#set page(width: 200pt, height: auto, margin: 10pt) +#set par(justify: true) +#set text(fill: gradient.conic(red, blue, angle: 45deg)) +#lorem(30) + +--- gradient-text-bad-relative --- +// Make sure they don't work when `relative: "self"`. +// Hint: 17-61 make sure to set `relative: auto` on your text fill +// Error: 17-61 gradients and patterns on text must be relative to the parent +#set text(fill: gradient.linear(red, blue, relative: "self")) + +--- gradient-text-global --- +// Test that gradient fills on text work for globally defined gradients. +#set page(width: 200pt, height: auto, margin: 10pt, background: { + rect(width: 100%, height: 30pt, fill: gradient.linear(red, blue)) +}) +#set par(justify: true) +#set text(fill: gradient.linear(red, blue)) +#lorem(30) + +--- gradient-text-dir --- +// Sanity check that the direction works on text. +#set page(width: 200pt, height: auto, margin: 10pt, background: { + rect(height: 100%, width: 30pt, fill: gradient.linear(dir: btt, red, blue)) +}) +#set par(justify: true) +#set text(fill: gradient.linear(dir: btt, red, blue)) +#lorem(30) + +--- gradient-text-in-container --- +// Test that gradient fills on text work for locally defined gradients. +#set page(width: auto, height: auto, margin: 10pt) +#show box: set text(fill: gradient.linear(..color.map.rainbow)) +Hello, #box[World]! + +--- gradient-text-rotate --- +// Test that gradients fills on text work with transforms. +#set page(width: auto, height: auto, margin: 10pt) +#show box: set text(fill: gradient.linear(..color.map.rainbow)) +#rotate(45deg, box[World]) + +--- gradient-text-decoration --- +#set text(fill: gradient.linear(red, blue)) + +Hello #underline[World]! \ +Hello #overline[World]! \ +Hello #strike[World]! \ + +--- gradient-transformed --- +// Test whether gradients work well when they are contained within a transform. +#let grad = gradient.linear(red, blue, green, purple, relative: "parent"); +#let my-rect = rect(width: 50pt, height: 50pt, fill: grad) +#set page( + height: 50pt, + width: 50pt, + margin: 2.5pt, +) +#place(top + right, scale(x: 200%, y: 130%, my-rect)) +#place(bottom + center, rotate(45deg, my-rect)) +#place(horizon + center, scale(x: 200%, y: 130%, rotate(45deg, my-rect))) + +--- gradient-presets --- +// Test all gradient presets. +#set page(width: 100pt, height: auto, margin: 0pt) +#set text(fill: white, size: 18pt) +#set text(top-edge: "bounds", bottom-edge: "bounds") + +#let presets = ( + ("turbo", color.map.turbo), + ("cividis", color.map.cividis), + ("rainbow", color.map.rainbow), + ("spectral", color.map.spectral), + ("viridis", color.map.viridis), + ("inferno", color.map.inferno), + ("magma", color.map.magma), + ("plasma", color.map.plasma), + ("rocket", color.map.rocket), + ("mako", color.map.mako), + ("vlag", color.map.vlag), + ("icefire", color.map.icefire), + ("flare", color.map.flare), + ("crest", color.map.crest), +) + +#stack( + spacing: 3pt, + ..presets.map(((name, preset)) => block( + width: 100%, + height: 20pt, + fill: gradient.linear(..preset), + align(center + horizon, smallcaps(name)), + )) +) + +// Test that gradients are applied correctly on equations. + +--- gradient-math-cancel --- +// Test on cancel +#show math.equation: set text(fill: gradient.linear(..color.map.rainbow)) +#show math.equation: box + +$ a dot cancel(5) = cancel(25) 5 x + cancel(5) 1 $ + +--- gradient-math-frac --- +// Test on frac +#show math.equation: set text(fill: gradient.linear(..color.map.rainbow)) +#show math.equation: box + +$ nabla dot bold(E) = frac(rho, epsilon_0) $ + +--- gradient-math-root --- +// Test on root +#show math.equation: set text(fill: gradient.linear(..color.map.rainbow)) +#show math.equation: box + +$ x_"1,2" = frac(-b +- sqrt(b^2 - 4 a c), 2 a) $ + +--- gradient-math-mat --- +// Test on matrix +#show math.equation: set text(fill: gradient.linear(..color.map.rainbow)) +#show math.equation: box + +$ A = mat( + 1, 2, 3; + 4, 5, 6; + 7, 8, 9 +) $ + +--- gradient-math-underover --- +// Test on underover +#show math.equation: set text(fill: gradient.linear(..color.map.rainbow)) +#show math.equation: box + +$ underline(X^2) $ +$ overline("hello, world!") $ + +--- gradient-math-dir --- +// Test a different direction +#show math.equation: set text(fill: gradient.linear(..color.map.rainbow, dir: ttb)) +#show math.equation: box + +$ A = mat( + 1, 2, 3; + 4, 5, 6; + 7, 8, 9 +) $ + +$ x_"1,2" = frac(-b +- sqrt(b^2 - 4 a c), 2 a) $ + +--- gradient-math-misc --- +// Test miscellaneous +#show math.equation: set text(fill: gradient.linear(..color.map.rainbow)) +#show math.equation: box + +$ hat(x) = bar x bar = vec(x, y, z) = tilde(x) = dot(x) $ +$ x prime = vec(1, 2, delim: "[") $ +$ sum_(i in NN) 1 + i $ +$ attach( + Pi, t: alpha, b: beta, + tl: 1, tr: 2+3, bl: 4+5, br: 6, +) $ + +--- gradient-math-radial --- +// Test radial gradient +#show math.equation: set text(fill: gradient.radial(..color.map.rainbow, center: (30%, 30%))) +#show math.equation: box + +$ A = mat( + 1, 2, 3; + 4, 5, 6; + 7, 8, 9 +) $ + +--- gradient-math-conic --- +// Test conic gradient +#show math.equation: set text(fill: gradient.conic(red, blue, angle: 45deg)) +#show math.equation: box + +$ A = mat( + 1, 2, 3; + 4, 5, 6; + 7, 8, 9 +) $ + + +--- gradient-kind --- +// Test gradient functions. +#test(gradient.linear(red, green, blue).kind(), gradient.linear) + +--- gradient-stops --- +#test(gradient.linear(red, green, blue).stops(), ((red, 0%), (green, 50%), (blue, 100%))) + +--- gradient-sample --- +#test(gradient.linear(red, green, blue, space: rgb).sample(0%), red) +#test(gradient.linear(red, green, blue, space: rgb).sample(25%), rgb("#97873b")) +#test(gradient.linear(red, green, blue, space: rgb).sample(50%), green) +#test(gradient.linear(red, green, blue, space: rgb).sample(75%), rgb("#17a08c")) +#test(gradient.linear(red, green, blue, space: rgb).sample(100%), blue) + +--- gradient-space --- +#test(gradient.linear(red, green, space: rgb).space(), rgb) +#test(gradient.linear(red, green, space: oklab).space(), oklab) +#test(gradient.linear(red, green, space: oklch).space(), oklch) +#test(gradient.linear(red, green, space: cmyk).space(), cmyk) +#test(gradient.linear(red, green, space: luma).space(), luma) +#test(gradient.linear(red, green, space: color.linear-rgb).space(), color.linear-rgb) +#test(gradient.linear(red, green, space: color.hsl).space(), color.hsl) +#test(gradient.linear(red, green, space: color.hsv).space(), color.hsv) + +--- gradient-relative --- +#test(gradient.linear(red, green, relative: "self").relative(), "self") +#test(gradient.linear(red, green, relative: "parent").relative(), "parent") +#test(gradient.linear(red, green).relative(), auto) + +--- gradient-angle --- +#test(gradient.linear(red, green).angle(), 0deg) +#test(gradient.linear(red, green, dir: ltr).angle(), 0deg) +#test(gradient.linear(red, green, dir: rtl).angle(), 180deg) +#test(gradient.linear(red, green, dir: ttb).angle(), 90deg) +#test(gradient.linear(red, green, dir: btt).angle(), 270deg) + +--- gradient-repeat --- +#test( + gradient.linear(red, green, blue).repeat(2).stops(), + ((red, 0%), (green, 25%), (blue, 50%), (red, 50%), (green, 75%), (blue, 100%)) +) +#test( + gradient.linear(red, green, blue).repeat(2, mirror: true).stops(), + ((red, 0%), (green, 25%), (blue, 50%), (green, 75%), (red, 100%)) +) + +--- gradient-repr --- +// Gradients +#set page(width: 400pt) +#set text(0.8em) +#gradient.linear(blue, red) \ +#gradient.linear(blue, red, dir: ttb) \ +#gradient.linear(blue, red, angle: 45deg, relative: "self") \ +#gradient.linear(blue, red, angle: 45deg, space: rgb) + +--- issue-2902-gradient-oklch-panic --- +// Minimal reproduction of #2902 +#set page(width: 15cm, height: auto, margin: 1em) +#set block(width: 100%, height: 1cm, above: 2pt) + +// Oklch +#block(fill: gradient.linear(red, purple, space: oklch)) +#block(fill: gradient.linear(..color.map.rainbow, space: oklch)) +#block(fill: gradient.linear(..color.map.plasma, space: oklch)) + +--- issue-2902-gradient-oklab-panic --- +#set page(width: 15cm, height: auto, margin: 1em) +#set block(width: 100%, height: 1cm, above: 2pt) + +// Oklab +#block(fill: gradient.linear(red, purple, space: oklab)) +#block(fill: gradient.linear(..color.map.rainbow, space: oklab)) +#block(fill: gradient.linear(..color.map.plasma, space: oklab)) + +--- issue-gradient-cmyk-encode --- +// Test that CMYK works on gradients +#set page(margin: 0pt, width: 100pt, height: auto) + +#let violet = cmyk(75%, 80%, 0%, 0%) +#let blue = cmyk(75%, 30%, 0%, 0%) + +#rect( + width: 100%, + height: 10pt, + fill: gradient.linear(violet, blue) +) + +#rect( + width: 100%, + height: 10pt, + fill: gradient.linear(rgb(violet), rgb(blue)) +) + +// In PDF format, this gradient can look different from the others. +// This is because PDF readers do weird things with CMYK. +#rect( + width: 100%, + height: 10pt, + fill: gradient.linear(violet, blue, space: cmyk) +) diff --git a/tests/suite/visualize/image.typ b/tests/suite/visualize/image.typ new file mode 100644 index 00000000..ac2d5af9 --- /dev/null +++ b/tests/suite/visualize/image.typ @@ -0,0 +1,122 @@ +// Test the `image` function. + +--- image-rgba-png-and-jpeg --- +// Test loading different image formats. + +// Load an RGBA PNG image. +#image("/assets/images/rhino.png") + +// Load an RGB JPEG image. +#set page(height: 60pt) +#image("/assets/images/tiger.jpg") + +--- image-sizing --- +// Test configuring the size and fitting behaviour of images. + +// Set width and height explicitly. +#box(image("/assets/images/rhino.png", width: 30pt)) +#box(image("/assets/images/rhino.png", height: 30pt)) + +// Set width and height explicitly and force stretching. +#image("/assets/images/monkey.svg", width: 100%, height: 20pt, fit: "stretch") + +// Make sure the bounding-box of the image is correct. +#align(bottom + right, image("/assets/images/tiger.jpg", width: 40pt, alt: "A tiger")) + +--- image-fit --- +// Test all three fit modes. +#set page(height: 50pt, margin: 0pt) +#grid( + columns: (1fr, 1fr, 1fr), + rows: 100%, + gutter: 3pt, + image("/assets/images/tiger.jpg", width: 100%, height: 100%, fit: "contain"), + image("/assets/images/tiger.jpg", width: 100%, height: 100%, fit: "cover"), + image("/assets/images/monkey.svg", width: 100%, height: 100%, fit: "stretch"), +) + +--- image-jump-to-next-page --- +// Does not fit to remaining height of page. +#set page(height: 60pt) +Stuff +#image("/assets/images/rhino.png") + +--- image-baseline-with-box --- +// Test baseline. +A #box(image("/assets/images/tiger.jpg", height: 1cm, width: 80%)) B + +--- image-svg-complex --- +// Test advanced SVG features. +#image("/assets/images/pattern.svg") + +--- image-svg-text --- +#set page(width: 250pt) + +#figure( + image("/assets/images/diagram.svg"), + caption: [A textful diagram], +) + +--- image-svg-text-font --- +#set page(width: 250pt) +#show image: set text(font: ("Roboto", "Noto Serif CJK SC")) + +#figure( + image("/assets/images/chinese.svg"), + caption: [Bilingual text] +) + +--- image-natural-dpi-sizing --- +// Test that images aren't upscaled. +// Image is just 48x80 at 220dpi. It should not be scaled to fit the page +// width, but rather max out at its natural size. +#image("/assets/images/f2t.jpg") + +--- image-file-not-found --- +// Error: 8-29 file not found (searched at tests/suite/visualize/path/does/not/exist) +#image("path/does/not/exist") + +--- image-bad-format --- +// Error: 2-22 unknown image format +#image("./image.typ") + +--- image-bad-svg --- +// Error: 2-33 failed to parse SVG (found closing tag 'g' instead of 'style' in line 4) +#image("/assets/images/bad.svg") + +--- image-decode-svg --- +// Test parsing from svg data +#image.decode(`<svg xmlns="http://www.w3.org/2000/svg" height="140" width="500"><ellipse cx="200" cy="80" rx="100" ry="50" style="fill:yellow;stroke:purple;stroke-width:2" /></svg>`.text, format: "svg") + +--- image-decode-bad-svg --- +// Error: 2-168 failed to parse SVG (missing root node) +#image.decode(`<svg height="140" width="500"><ellipse cx="200" cy="80" rx="100" ry="50" style="fill:yellow;stroke:purple;stroke-width:2" /></svg>`.text, format: "svg") + +--- image-decode-detect-format --- +// Test format auto detect +#image.decode(read("/assets/images/tiger.jpg", encoding: none), width: 80%) + +--- image-decode-specify-format --- +// Test format manual +#image.decode(read("/assets/images/tiger.jpg", encoding: none), format: "jpg", width: 80%) + +--- image-decode-specify-wrong-format --- +// Error: 2-91 failed to decode image (Format error decoding Png: Invalid PNG signature.) +#image.decode(read("/assets/images/tiger.jpg", encoding: none), format: "png", width: 80%) + +--- issue-870-image-rotation --- +// Ensure that EXIF rotation is applied. +// https://github.com/image-rs/image/issues/1045 +// File is from https://magnushoff.com/articles/jpeg-orientation/ +#image("/assets/images/f2t.jpg", width: 10pt) + +--- issue-measure-image --- +// Test that image measurement doesn't turn `inf / some-value` into 0pt. +#context { + let size = measure(image("/assets/images/tiger.jpg")) + test(size, (width: 1024pt, height: 670pt)) +} + +--- issue-2051-new-cm-svg --- +#set text(font: "New Computer Modern") +#image("/assets/images/diagram.svg") diff --git a/tests/suite/visualize/line.typ b/tests/suite/visualize/line.typ new file mode 100644 index 00000000..7259f72b --- /dev/null +++ b/tests/suite/visualize/line.typ @@ -0,0 +1,92 @@ +// Test lines. + +--- line-basic --- +#set page(height: 60pt) +#box({ + set line(stroke: 0.75pt) + place(line(end: (0.4em, 0pt))) + place(line(start: (0pt, 0.4em), end: (0pt, 0pt))) + line(end: (0.6em, 0.6em)) +}) Hello #box(line(length: 1cm))! + +#line(end: (70%, 50%)) + +--- line-positioning --- +// Test the angle argument and positioning. + +#set page(fill: rgb("0B1026")) +#set line(stroke: white) + +#let star(size, ..args) = box(width: size, height: size)[ + #set text(spacing: 0%) + #set line(..args) + #set align(left) + #v(30%) + #place(line(length: +30%, start: (09.0%, 02%))) + #place(line(length: +30%, start: (38.7%, 02%), angle: -72deg)) + #place(line(length: +30%, start: (57.5%, 02%), angle: 252deg)) + #place(line(length: +30%, start: (57.3%, 02%))) + #place(line(length: -30%, start: (88.0%, 02%), angle: -36deg)) + #place(line(length: +30%, start: (73.3%, 48%), angle: 252deg)) + #place(line(length: -30%, start: (73.5%, 48%), angle: 36deg)) + #place(line(length: +30%, start: (25.4%, 48%), angle: -36deg)) + #place(line(length: +30%, start: (25.6%, 48%), angle: -72deg)) + #place(line(length: +32%, start: (8.50%, 02%), angle: 34deg)) +] + +#align(center, grid( + columns: 3, + column-gutter: 10pt, + ..((star(20pt, stroke: 0.5pt),) * 9) +)) + +--- line-stroke --- +// Some simple test lines +#line(length: 60pt, stroke: red) +#v(3pt) +#line(length: 60pt, stroke: 2pt) +#v(3pt) +#line(length: 60pt, stroke: blue + 1.5pt) +#v(3pt) +#line(length: 60pt, stroke: (paint: red, thickness: 1pt, dash: "dashed")) +#v(3pt) +#line(length: 60pt, stroke: (paint: red, thickness: 4pt, cap: "round")) + +--- line-stroke-set --- +// Set rules with stroke +#set line(stroke: (paint: red, thickness: 1pt, cap: "butt", dash: "dash-dotted")) +#line(length: 60pt) +#v(3pt) +#line(length: 60pt, stroke: blue) +#v(3pt) +#line(length: 60pt, stroke: (dash: none)) + +--- line-stroke-dash --- +// Dashing +#line(length: 60pt, stroke: (paint: red, thickness: 1pt, dash: ("dot", 1pt))) +#v(3pt) +#line(length: 60pt, stroke: (paint: red, thickness: 1pt, dash: ("dot", 1pt, 4pt, 2pt))) +#v(3pt) +#line(length: 60pt, stroke: (paint: red, thickness: 1pt, dash: (array: ("dot", 1pt, 4pt, 2pt), phase: 5pt))) +#v(3pt) +#line(length: 60pt, stroke: (paint: red, thickness: 1pt, dash: ())) +#v(3pt) +#line(length: 60pt, stroke: (paint: red, thickness: 1pt, dash: (1pt, 3pt, 9pt))) + +--- line-stroke-field-typo --- +// Error: 29-56 unexpected key "thicknes", valid keys are "paint", "thickness", "cap", "join", "dash", and "miter-limit" +#line(length: 60pt, stroke: (paint: red, thicknes: 1pt)) + +--- line-stroke-bad-dash-kind --- +// Error: 29-55 expected "solid", "dotted", "densely-dotted", "loosely-dotted", "dashed", "densely-dashed", "loosely-dashed", "dash-dotted", "densely-dash-dotted", "loosely-dash-dotted", array, dictionary, none, or auto +#line(length: 60pt, stroke: (paint: red, dash: "dash")) + +--- line-bad-point-array --- +// Test errors. + +// Error: 12-19 point array must contain exactly two entries +#line(end: (50pt,)) + +--- line-bad-point-component-type --- +// Error: 14-26 expected relative length, found angle +#line(start: (3deg, 10pt), length: 5cm) diff --git a/tests/suite/visualize/path.typ b/tests/suite/visualize/path.typ new file mode 100644 index 00000000..10955f14 --- /dev/null +++ b/tests/suite/visualize/path.typ @@ -0,0 +1,52 @@ +// Test paths. + +--- path --- +#set page(height: 200pt, width: 200pt) +#table( + columns: (1fr, 1fr), + rows: (1fr, 1fr), + align: center + horizon, + path( + fill: red, + closed: true, + ((0%, 0%), (4%, -4%)), + ((50%, 50%), (4%, -4%)), + ((0%, 50%), (4%, 4%)), + ((50%, 0%), (4%, 4%)), + ), + path( + fill: purple, + stroke: 1pt, + (0pt, 0pt), + (30pt, 30pt), + (0pt, 30pt), + (30pt, 0pt), + ), + path( + fill: blue, + stroke: 1pt, + closed: true, + ((30%, 0%), (35%, 30%), (-20%, 0%)), + ((30%, 60%), (-20%, 0%), (0%, 0%)), + ((50%, 30%), (60%, -30%), (60%, 0%)), + ), + path( + stroke: 5pt, + closed: true, + (0pt, 30pt), + (30pt, 30pt), + (15pt, 0pt), + ), +) + +--- path-bad-vertex --- +// Error: 7-9 path vertex must have 1, 2, or 3 points +#path(()) + +--- path-bad-point-count --- +// Error: 7-47 path vertex must have 1, 2, or 3 points +#path(((0%, 0%), (0%, 0%), (0%, 0%), (0%, 0%))) + +--- path-bad-point-array --- +// Error: 7-31 point array must contain exactly two entries +#path(((0%, 0%), (0%, 0%, 0%))) diff --git a/tests/suite/visualize/pattern.typ b/tests/suite/visualize/pattern.typ new file mode 100644 index 00000000..08051ed2 --- /dev/null +++ b/tests/suite/visualize/pattern.typ @@ -0,0 +1,131 @@ +// Test patterns. + +--- pattern-line --- +// Tests that simple patterns work. +#set page(width: auto, height: auto, margin: 0pt) +#let pat = pattern(size: (10pt, 10pt), line(stroke: 4pt, start: (0%, 0%), end: (100%, 100%))) +#rect(width: 50pt, height: 50pt, fill: pat) + +--- pattern-lines --- +#set page(width: auto, height: auto, margin: 0pt) + +#let pat = pattern(size: (10pt, 10pt), { + place(line(stroke: 4pt, start: (0%, 0%), end: (100%, 100%))) + place(line(stroke: 4pt, start: (100%,0%), end: (200%, 100%))) + place(line(stroke: 4pt, start: (0%,100%), end: (100%, 200%))) + place(line(stroke: 4pt, start: (-100%,0%), end: (0%, 100%))) + place(line(stroke: 4pt, start: (0%,-100%), end: (100%, 0%))) +}) +#rect(width: 50pt, height: 50pt, fill: pat) + +--- pattern-relative-self --- +// Test with relative set to `"self"` +#let pat(..args) = pattern(size: (30pt, 30pt), ..args)[ + #place(top + left, line(start: (0%, 0%), end: (100%, 100%), stroke: 1pt)) + #place(top + left, line(start: (0%, 100%), end: (100%, 0%), stroke: 1pt)) +] + +#set page(fill: pat(), width: 100pt, height: 100pt) + +#rect(fill: pat(relative: "self"), width: 100%, height: 100%, stroke: 1pt) + +--- pattern-relative-parent --- +// Test with relative set to `"parent"` +#let pat(..args) = pattern(size: (30pt, 30pt), ..args)[ + #place(top + left, line(start: (0%, 0%), end: (100%, 100%), stroke: 1pt)) + #place(top + left, line(start: (0%, 100%), end: (100%, 0%), stroke: 1pt)) +] + +#set page(fill: pat(), width: 100pt, height: 100pt) + +#rect(fill: pat(relative: "parent"), width: 100%, height: 100%, stroke: 1pt) + +--- pattern-small --- +// Tests small patterns for pixel accuracy. +#box( + width: 8pt, + height: 1pt, + fill: pattern(size: (1pt, 1pt), square(size: 1pt, fill: black)) +) +#v(-1em) +#box( + width: 8pt, + height: 1pt, + fill: pattern(size: (2pt, 1pt), square(size: 1pt, fill: black)) +) + +--- pattern-zero-sized --- +// Error: 15-52 pattern tile size must be non-zero +// Hint: 15-52 try setting the size manually +#line(stroke: pattern(path((0pt, 0pt), (1em, 0pt)))) + +--- pattern-spacing-negative --- +// Test with spacing set to `(-10pt, -10pt)` +#let pat(..args) = pattern(size: (30pt, 30pt), ..args)[ + #square(width: 100%, height: 100%, stroke: 1pt, fill: blue) +] + +#set page(width: 100pt, height: 100pt) + +#rect(fill: pat(spacing: (-10pt, -10pt)), width: 100%, height: 100%, stroke: 1pt) + +--- pattern-spacing-zero --- +// Test with spacing set to `(0pt, 0pt)` +#let pat(..args) = pattern(size: (30pt, 30pt), ..args)[ + #square(width: 100%, height: 100%, stroke: 1pt, fill: blue) +] + +#set page(width: 100pt, height: 100pt) + +#rect(fill: pat(spacing: (0pt, 0pt)), width: 100%, height: 100%, stroke: 1pt) + +--- pattern-spacing-positive --- +// Test with spacing set to `(10pt, 10pt)` +#let pat(..args) = pattern(size: (30pt, 30pt), ..args)[ + #square(width: 100%, height: 100%, stroke: 1pt, fill: blue) +] + +#set page(width: 100pt, height: 100pt) + +#rect(fill: pat(spacing: (10pt, 10pt,)), width: 100%, height: 100%, stroke: 1pt) + +--- pattern-stroke --- +// Test pattern on strokes +#align( + center + top, + square( + size: 50pt, + stroke: 5pt + pattern( + size: (5pt, 5pt), + align(horizon + center, circle(fill: blue, radius: 2.5pt)) + ) + ) +) + +--- pattern-text --- +// Test a pattern on some text +// You shouldn't be able to see the text, if you can then +// that means that the transform matrices are not being +// applied to the text correctly. +#let pat = pattern( + size: (30pt, 30pt), + relative: "parent", + square(size: 30pt, fill: gradient.conic(..color.map.rainbow)) +); + +#set page( + width: 140pt, + height: 140pt, + fill: pat +) + +#rotate(45deg, scale(x: 50%, y: 70%, rect( + width: 100%, + height: 100%, + stroke: 1pt, +)[ + #lorem(10) + + #set text(fill: pat) + #lorem(10) +])) diff --git a/tests/suite/visualize/polygon.typ b/tests/suite/visualize/polygon.typ new file mode 100644 index 00000000..a3f4c8ef --- /dev/null +++ b/tests/suite/visualize/polygon.typ @@ -0,0 +1,51 @@ +// Test polygons. + +--- polygon --- +#set page(width: 50pt) +#set polygon(stroke: 0.75pt, fill: blue) + +// These are not visible, but should also not give an error +#polygon() +#polygon((0em, 0pt)) +#polygon((0pt, 0pt), (10pt, 0pt)) +#polygon.regular(size: 0pt, vertices: 9) + +#polygon((5pt, 0pt), (0pt, 10pt), (10pt, 10pt)) +#polygon( + (0pt, 0pt), (5pt, 5pt), (10pt, 0pt), + (15pt, 5pt), + (5pt, 10pt) +) +#polygon(stroke: none, (5pt, 0pt), (0pt, 10pt), (10pt, 10pt)) +#polygon(stroke: 3pt, fill: none, (5pt, 0pt), (0pt, 10pt), (10pt, 10pt)) + +// Relative size +#polygon((0pt, 0pt), (100%, 5pt), (50%, 10pt)) + +// Antiparallelogram +#polygon((0pt, 5pt), (5pt, 0pt), (0pt, 10pt), (5pt, 15pt)) + +// Self-intersections +#polygon((0pt, 10pt), (30pt, 20pt), (0pt, 30pt), (20pt, 0pt), (20pt, 35pt)) + +// Regular polygon; should have equal side lengths +#for k in range(3, 9) {polygon.regular(size: 30pt, vertices: k,)} + +--- polygon-line-join --- +// Line joins +#stack( + dir: ltr, + spacing: 1em, + polygon(stroke: (thickness: 4pt, paint: blue, join: "round"), + (0pt, 20pt), (15pt, 0pt), (0pt, 40pt), (15pt, 45pt)), + polygon(stroke: (thickness: 4pt, paint: blue, join: "bevel"), + (0pt, 20pt), (15pt, 0pt), (0pt, 40pt), (15pt, 45pt)), + polygon(stroke: (thickness: 4pt, paint: blue, join: "miter"), + (0pt, 20pt), (15pt, 0pt), (0pt, 40pt), (15pt, 45pt)), + polygon(stroke: (thickness: 4pt, paint: blue, join: "miter", miter-limit: 20.0), + (0pt, 20pt), (15pt, 0pt), (0pt, 40pt), (15pt, 45pt)), +) + +--- polygon-bad-point-array --- +// Error: 10-17 point array must contain exactly two entries +#polygon((50pt,)) diff --git a/tests/suite/visualize/rect.typ b/tests/suite/visualize/rect.typ new file mode 100644 index 00000000..f84fafcb --- /dev/null +++ b/tests/suite/visualize/rect.typ @@ -0,0 +1,107 @@ +// Test the `rect` function. + +--- rect --- +// Default rectangle. +#rect() + +--- rect-customization --- +#set page(width: 150pt) + +// Fit to text. +#rect(fill: conifer)[Textbox] + +// Empty with fixed width and height. +#block(rect( + height: 15pt, + fill: rgb("46b3c2"), + stroke: 2pt + rgb("234994"), +)) + +// Fixed width, text height. +#rect(width: 2cm, fill: rgb("9650d6"))[Fixed and padded] + +// Page width, fixed height. +#rect(height: 1cm, width: 100%, fill: rgb("734ced"))[Topleft] + +// These are inline with text. +{#box(rect(width: 0.5in, height: 7pt, fill: rgb("d6cd67"))) + #box(rect(width: 0.5in, height: 7pt, fill: rgb("edd466"))) + #box(rect(width: 0.5in, height: 7pt, fill: rgb("e3be62")))} + +// Rounded corners. +#stack( + dir: ltr, + spacing: 1fr, + rect(width: 2cm, radius: 30%), + rect(width: 1cm, radius: (left: 10pt, right: 5pt)), + rect(width: 1.25cm, radius: ( + top-left: 2pt, + top-right: 5pt, + bottom-right: 8pt, + bottom-left: 11pt + )), +) + +// Different strokes. +#set rect(stroke: (right: red)) +#rect(width: 100%, fill: lime, stroke: (x: 5pt, y: 1pt)) + +--- rect-stroke --- +// Rectangle strokes +#rect(width: 20pt, height: 20pt, stroke: red) +#v(3pt) +#rect(width: 20pt, height: 20pt, stroke: (rest: red, top: (paint: blue, dash: "dashed"))) +#v(3pt) +#rect(width: 20pt, height: 20pt, stroke: (thickness: 5pt, join: "round")) + +--- red-stroke-bad-type --- +// Error: 15-21 expected length, color, gradient, pattern, dictionary, stroke, none, or auto, found array +#rect(stroke: (1, 2)) + +--- rect-fill-stroke --- +#let variant = rect.with(width: 20pt, height: 10pt) +#let items = for (i, item) in ( + variant(stroke: none), + variant(), + variant(fill: none), + variant(stroke: 2pt), + variant(stroke: eastern), + variant(stroke: eastern + 2pt), + variant(fill: eastern), + variant(fill: eastern, stroke: none), + variant(fill: forest, stroke: none), + variant(fill: forest, stroke: conifer), + variant(fill: forest, stroke: black + 2pt), + variant(fill: forest, stroke: conifer + 2pt), +).enumerate() { + (align(horizon)[#(i + 1).], item, []) +} + +#grid( + columns: (auto, auto, 1fr, auto, auto, 0fr), + gutter: 5pt, + ..items, +) + +--- rect-radius-bad-key --- +// Error: 15-38 unexpected key "cake", valid keys are "top-left", "top-right", "bottom-right", "bottom-left", "left", "top", "right", "bottom", and "rest" +#rect(radius: (left: 10pt, cake: 5pt)) + +--- issue-1825-rect-overflow --- +#set page(width: 17.8cm) +#set par(justify: true) +#rect(lorem(70)) + +--- issue-3264-rect-negative-dimensions --- +// Negative dimensions +#rect(width: -1cm, fill: gradient.linear(red, blue))[Reverse left] + +#rect(width: 1cm, fill: gradient.linear(red, blue))[Left] + +#align(center, rect(width: -1cm, fill: gradient.linear(red, blue))[Reverse center]) + +#align(center, rect(width: 1cm, fill: gradient.linear(red, blue))[Center]) + +#align(right, rect(width: -1cm, fill: gradient.linear(red, blue))[Reverse right]) + +#align(right, rect(width: 1cm, fill: gradient.linear(red, blue))[Right]) diff --git a/tests/suite/visualize/square.typ b/tests/suite/visualize/square.typ new file mode 100644 index 00000000..caa1fc21 --- /dev/null +++ b/tests/suite/visualize/square.typ @@ -0,0 +1,146 @@ +// Test the `square` function. + +--- square --- +// Default square. +#box(square()) +#box(square[hey!]) + +--- square-auto-sized --- +// Test auto-sized square. +#square(fill: eastern)[ + #set text(fill: white, weight: "bold") + Typst +] + +--- square-relatively-sized-child --- +// Test relative-sized child. +#square(fill: eastern)[ + #rect(width: 10pt, height: 5pt, fill: conifer) + #rect(width: 40%, height: 5pt, stroke: conifer) +] + +--- square-contents-overflow --- +// Test text overflowing height. +#set page(width: 75pt, height: 100pt) +#square(fill: conifer)[ + But, soft! what light through yonder window breaks? +] + +--- square-height-limited --- +// Test that square does not overflow page. +#set page(width: 100pt, height: 75pt) +#square(fill: conifer)[ + But, soft! what light through yonder window breaks? +] + +--- square-size-width-and-height --- +// Size wins over width and height. +// Error: 09-20 unexpected argument: width +#square(width: 10cm, height: 20cm, size: 1cm, fill: rgb("eb5278")) + +--- square-relative-size --- +// Test relative width and height and size that is smaller +// than default size. +#set page(width: 120pt, height: 70pt) +#set align(bottom) +#let centered = align.with(center + horizon) +#stack( + dir: ltr, + spacing: 1fr, + square(width: 50%, centered[A]), + square(height: 50%), + stack( + square(size: 10pt), + square(size: 20pt, centered[B]) + ), +) + +--- square-circle-alignment --- +// Test alignment in automatically sized square and circle. +#set text(8pt) +#box(square(inset: 4pt)[ + Hey there, #align(center + bottom, rotate(180deg, [you!])) +]) +#box(circle(align(center + horizon, [Hey.]))) + +--- square-circle-overspecified --- +// Test that minimum wins if both width and height are given. +#stack( + dir: ltr, + spacing: 2pt, + square(width: 20pt, height: 40pt), + circle(width: 20%, height: 100pt), +) + +--- square-height-limited-stack --- +// Test square that is limited by region size. +#set page(width: 20pt, height: 10pt, margin: 0pt) +#stack(dir: ltr, square(fill: forest), square(fill: conifer)) + +--- square-overflow --- +// Test that square doesn't overflow due to its aspect ratio. +#set page(width: 40pt, height: 25pt, margin: 5pt) +#square(width: 100%) +#square(width: 100%)[Hello there] + +--- square-size-relative-invalid --- +// Size cannot be relative because we wouldn't know +// relative to which axis. +// Error: 15-18 expected length or auto, found ratio +#square(size: 50%) + +--- square-rect-rounded --- +#set square(size: 20pt, stroke: 4pt) + +// no radius for non-rounded corners +#stack( + dir: ltr, + square(), + h(10pt), + square(radius: 0pt), + h(10pt), + square(radius: -10pt), +) + +#stack( + dir: ltr, + square(), + h(10pt), + square(radius: 0%), + h(10pt), + square(radius: -10%), +) + +// small values for small radius +#stack( + dir: ltr, + square(radius: 1pt), + h(10pt), + square(radius: 5%), + h(10pt), + square(radius: 2pt), +) + +// large values for large radius or circle +#stack( + dir: ltr, + square(radius: 8pt), + h(10pt), + square(radius: 10pt), + h(10pt), + square(radius: 12pt), +) + +#stack( + dir: ltr, + square(radius: 45%), + h(10pt), + square(radius: 50%), + h(10pt), + square(radius: 55%), +) + +--- square-base --- +// Test that square sets correct base for its content. +#set page(height: 80pt) +#square(width: 40%, rect(width: 60%, height: 80%)) diff --git a/tests/suite/visualize/stroke.typ b/tests/suite/visualize/stroke.typ new file mode 100644 index 00000000..b03c96c5 --- /dev/null +++ b/tests/suite/visualize/stroke.typ @@ -0,0 +1,171 @@ +// Test lines. + +--- stroke-constructor --- +// Converting to stroke +#assert.eq(stroke(red).paint, red) +#assert.eq(stroke(red).thickness, auto) +#assert.eq(stroke(2pt).paint, auto) +#assert.eq(stroke((cap: "round", paint: blue)).cap, "round") +#assert.eq(stroke((cap: auto, paint: blue)).cap, auto) +#assert.eq(stroke((cap: auto, paint: blue)).thickness, auto) + +// Constructing with named arguments +#assert.eq(stroke(paint: blue, thickness: 8pt), 8pt + blue) +#assert.eq(stroke(thickness: 2pt), stroke(2pt)) +#assert.eq(stroke(cap: "round").thickness, auto) +#assert.eq(stroke(cap: "round", thickness: auto).thickness, auto) + +--- stroke-constructor-unknown-key --- +// Error: 9-21 unexpected key "foo", valid keys are "paint", "thickness", "cap", "join", "dash", and "miter-limit" +#stroke((foo: "bar")) + +--- stroke-fields-simple --- +// Test stroke fields for simple strokes. +#test((1em + blue).paint, blue) +#test((1em + blue).thickness, 1em) +#test((1em + blue).cap, auto) +#test((1em + blue).join, auto) +#test((1em + blue).dash, auto) +#test((1em + blue).miter-limit, auto) + +--- stroke-fields-complex --- +// Test complex stroke fields. +#let r1 = rect(stroke: (paint: cmyk(1%, 2%, 3%, 4%), thickness: 4em + 2pt, cap: "round", join: "bevel", miter-limit: 5.0, dash: none)) +#let r2 = rect(stroke: (paint: cmyk(1%, 2%, 3%, 4%), thickness: 4em + 2pt, cap: "round", join: "bevel", miter-limit: 5.0, dash: (3pt, "dot", 4em))) +#let r3 = rect(stroke: (paint: cmyk(1%, 2%, 3%, 4%), thickness: 4em + 2pt, cap: "round", join: "bevel", dash: (array: (3pt, "dot", 4em), phase: 5em))) +#let s1 = r1.stroke +#let s2 = r2.stroke +#let s3 = r3.stroke +#test(s1.paint, cmyk(1%, 2%, 3%, 4%)) +#test(s1.thickness, 4em + 2pt) +#test(s1.cap, "round") +#test(s1.join, "bevel") +#test(s1.miter-limit, 5.0) +#test(s3.miter-limit, auto) +#test(s1.dash, none) +#test(s2.dash, (array: (3pt, "dot", 4em), phase: 0pt)) +#test(s3.dash, (array: (3pt, "dot", 4em), phase: 5em)) + +--- stroke-zero-thickness --- +// 0pt strokes must function exactly like 'none' strokes and not draw anything +#rect(width: 10pt, height: 10pt, stroke: none) +#rect(width: 10pt, height: 10pt, stroke: 0pt) +#rect(width: 10pt, height: 10pt, stroke: none, fill: blue) +#rect(width: 10pt, height: 10pt, stroke: 0pt + red, fill: blue) + +#line(length: 30pt, stroke: 0pt) +#line(length: 30pt, stroke: (paint: red, thickness: 0pt, dash: ("dot", 1pt))) + +#table(columns: 2, stroke: none)[A][B] +#table(columns: 2, stroke: 0pt)[A][B] + +#path( + fill: red, + stroke: none, + closed: true, + ((0%, 0%), (4%, -4%)), + ((50%, 50%), (4%, -4%)), + ((0%, 50%), (4%, 4%)), + ((50%, 0%), (4%, 4%)), +) + +#path( + fill: red, + stroke: 0pt, + closed: true, + ((0%, 0%), (4%, -4%)), + ((50%, 50%), (4%, -4%)), + ((0%, 50%), (4%, 4%)), + ((50%, 0%), (4%, 4%)), +) + +--- stroke-text --- +#set text(size: 20pt) +#set page(width: auto) +#let v = [测试字体Test] + +#text(stroke: 0.3pt + red, v) + +#text(stroke: 0.7pt + red, v) + +#text(stroke: 7pt + red, v) + +#text(stroke: (paint: blue, thickness: 1pt, dash: "dashed"), v) + +#text(stroke: 1pt + gradient.linear(..color.map.rainbow), v) + +--- stroke-folding --- +// Test stroke folding. +#let sq(..args) = box(square(size: 10pt, ..args)) + +#set square(stroke: none) +#sq() +#set square(stroke: auto) +#sq() +#sq(fill: teal) +#sq(stroke: 2pt) +#sq(stroke: blue) +#sq(fill: teal, stroke: blue) +#sq(fill: teal, stroke: 2pt + blue) + +--- stroke-composition --- +// Test stroke composition. +#set square(stroke: 4pt) +#set text(font: "Roboto") +#stack( + dir: ltr, + square( + stroke: (left: red, top: yellow, right: green, bottom: blue), + radius: 50%, align(center+horizon)[*G*], + inset: 8pt + ), + h(0.5cm), + square( + stroke: (left: red, top: yellow + 8pt, right: green, bottom: blue + 2pt), + radius: 50%, align(center+horizon)[*G*], + inset: 8pt + ), + h(0.5cm), + square( + stroke: (left: red, top: yellow, right: green, bottom: blue), + radius: 100%, align(center+horizon)[*G*], + inset: 8pt + ), +) + +// Join between different solid strokes +#set square(size: 20pt, stroke: 2pt) +#set square(stroke: (left: green + 4pt, top: black + 2pt, right: blue, bottom: black + 2pt)) +#stack( + dir: ltr, + square(), + h(0.2cm), + square(radius: (top-left: 0pt, rest: 1pt)), + h(0.2cm), + square(radius: (top-left: 0pt, rest: 8pt)), + h(0.2cm), + square(radius: (top-left: 0pt, rest: 100pt)), +) + +// Join between solid and dotted strokes +#set square(stroke: (left: green + 4pt, top: black + 2pt, right: (paint: blue, dash: "dotted"), bottom: (paint: black, dash: "dotted"))) +#stack( + dir: ltr, + square(), + h(0.2cm), + square(radius: (top-left: 0pt, rest: 1pt)), + h(0.2cm), + square(radius: (top-left: 0pt, rest: 8pt)), + h(0.2cm), + square(radius: (top-left: 0pt, rest: 100pt)), +) + +--- issue-3700-deformed-stroke --- +// Test shape fill & stroke for specific values that used to make the stroke +// deformed. +#rect( + radius: 1mm, + width: 100%, + height: 10pt, + stroke: (left: rgb("46b3c2") + 16.0mm), +) diff --git a/tests/typ/autocomplete/showcase.typ b/tests/typ/autocomplete/showcase.typ deleted file mode 100644 index 8ea94f2e..00000000 --- a/tests/typ/autocomplete/showcase.typ +++ /dev/null @@ -1,13 +0,0 @@ -// Autocomplete: true -// Ref: false - ---- -// Autocomplete contains: -1 "int", "if conditional" -// Autocomplete excludes: -1 "foo" -#i - ---- - -// Autocomplete contains: -1 "insert", "remove", "len", "all" -// Autocomplete excludes: -1 "foobar", "foo", -#(). diff --git a/tests/typ/bugs/1050-terms-indent.typ b/tests/typ/bugs/1050-terms-indent.typ deleted file mode 100644 index 82376820..00000000 --- a/tests/typ/bugs/1050-terms-indent.typ +++ /dev/null @@ -1,11 +0,0 @@ -#set page(width: 200pt) -#set par(first-line-indent: 0.5cm) - -- #lorem(10) -- #lorem(10) - -+ #lorem(10) -+ #lorem(10) - -/ Term 1: #lorem(10) -/ Term 2: #lorem(10) diff --git a/tests/typ/bugs/1240-stack-fr.typ b/tests/typ/bugs/1240-stack-fr.typ deleted file mode 100644 index fa49dce7..00000000 --- a/tests/typ/bugs/1240-stack-fr.typ +++ /dev/null @@ -1,18 +0,0 @@ -// This issue is sort of horrible: When you write `h(1fr)` in a `stack` instead -// of directly `1fr`, things go awry. To fix this, we now transparently detect -// h/v children. -// -// https://github.com/typst/typst/issues/1240 - ---- -#stack(dir: ltr, [a], 1fr, [b], 1fr, [c]) -#stack(dir: ltr, [a], h(1fr), [b], h(1fr), [c]) - ---- -#set page(height: 60pt) -#stack( - dir: ltr, - spacing: 1fr, - stack([a], 1fr, [b]), - stack([a], v(1fr), [b]), -) diff --git a/tests/typ/bugs/1597-cite-footnote.typ b/tests/typ/bugs/1597-cite-footnote.typ deleted file mode 100644 index cc231e2a..00000000 --- a/tests/typ/bugs/1597-cite-footnote.typ +++ /dev/null @@ -1,12 +0,0 @@ -// Tests that when a citation footnote is pushed to next page, things still -// work as expected. -// -// Issue: https://github.com/typst/typst/issues/1597 - ---- -#set page(height: 60pt) -#lorem(4) - -#footnote[@netwok] -#show bibliography: none -#bibliography("/assets/bib/works.bib") diff --git a/tests/typ/bugs/2044-invalid-parsed-ident.typ b/tests/typ/bugs/2044-invalid-parsed-ident.typ deleted file mode 100644 index 5e4b560c..00000000 --- a/tests/typ/bugs/2044-invalid-parsed-ident.typ +++ /dev/null @@ -1,6 +0,0 @@ -// In this bug, the dot at the end was causing the right parenthesis to be -// parsed as an identifier instead of the closing right parenthesis. -// Issue: https://github.com/typst/typst/issues/2044 - -$floor(phi.alt.)$ -$floor(phi.alt. )$ diff --git a/tests/typ/bugs/2105-linebreak-tofu.typ b/tests/typ/bugs/2105-linebreak-tofu.typ deleted file mode 100644 index 4dd5a244..00000000 --- a/tests/typ/bugs/2105-linebreak-tofu.typ +++ /dev/null @@ -1 +0,0 @@ -#linebreak()中文 diff --git a/tests/typ/bugs/2595-float-overlap.typ b/tests/typ/bugs/2595-float-overlap.typ deleted file mode 100644 index 7c7f68c9..00000000 --- a/tests/typ/bugs/2595-float-overlap.typ +++ /dev/null @@ -1,13 +0,0 @@ -#set page(height: 80pt) - -Start. - -#place(auto, float: true, [ - #block(height: 100%, width: 100%, fill: aqua) -]) - -#place(auto, float: true, [ - #block(height: 100%, width: 100%, fill: red) -]) - -#lorem(20) diff --git a/tests/typ/bugs/2650-cjk-latin-spacing-meta.typ b/tests/typ/bugs/2650-cjk-latin-spacing-meta.typ deleted file mode 100644 index 12c7ea41..00000000 --- a/tests/typ/bugs/2650-cjk-latin-spacing-meta.typ +++ /dev/null @@ -1,5 +0,0 @@ -// https://github.com/typst/typst/issues/2650 - -测a试 - -测#context [a]试 diff --git a/tests/typ/bugs/2715-float-order.typ b/tests/typ/bugs/2715-float-order.typ deleted file mode 100644 index af0684a1..00000000 --- a/tests/typ/bugs/2715-float-order.typ +++ /dev/null @@ -1,19 +0,0 @@ -#set page(height: 180pt) -#set figure(placement: auto) - -#figure( - rect(height: 60pt), - caption: [Rectangle I], -) - -#figure( - rect(height: 50pt), - caption: [Rectangle II], -) - -#figure( - circle(), - caption: [Circle], -) - -#lorem(20) diff --git a/tests/typ/bugs/2821-missing-fields.typ b/tests/typ/bugs/2821-missing-fields.typ deleted file mode 100644 index 0fec2043..00000000 --- a/tests/typ/bugs/2821-missing-fields.typ +++ /dev/null @@ -1,9 +0,0 @@ -// Issue #2821: Setting a figure's supplement to none removes the field -// Ref: false - ---- -#show figure.caption: it => { - assert(it.has("supplement")) - assert(it.supplement == none) -} -#figure([], caption: [], supplement: none) diff --git a/tests/typ/bugs/2902-gradient-oklch-panic.typ b/tests/typ/bugs/2902-gradient-oklch-panic.typ deleted file mode 100644 index 6e09df52..00000000 --- a/tests/typ/bugs/2902-gradient-oklch-panic.typ +++ /dev/null @@ -1,20 +0,0 @@ -// Minimal reproduction of #2902 -// Ref: false - ---- -#set page(width: 15cm, height: auto, margin: 1em) -#set block(width: 100%, height: 1cm, above: 2pt) - -// Oklch -#block(fill: gradient.linear(red, purple, space: oklch)) -#block(fill: gradient.linear(..color.map.rainbow, space: oklch)) -#block(fill: gradient.linear(..color.map.plasma, space: oklch)) - ---- -#set page(width: 15cm, height: auto, margin: 1em) -#set block(width: 100%, height: 1cm, above: 2pt) - -// Oklab -#block(fill: gradient.linear(red, purple, space: oklab)) -#block(fill: gradient.linear(..color.map.rainbow, space: oklab)) -#block(fill: gradient.linear(..color.map.plasma, space: oklab)) diff --git a/tests/typ/bugs/3082-chinese-punctuation.typ b/tests/typ/bugs/3082-chinese-punctuation.typ deleted file mode 100644 index 82cab6f6..00000000 --- a/tests/typ/bugs/3082-chinese-punctuation.typ +++ /dev/null @@ -1,4 +0,0 @@ -#set text(font: "Noto Serif CJK TC", lang: "zh") -#set page(width: 230pt) - -課有手冬,朱得過已誰卜服見以大您即乙太邊良,因且行肉因和拉幸,念姐遠米巴急(abc0),松黃貫誰。 diff --git a/tests/typ/bugs/3110-no-type-ctor-or-field.typ b/tests/typ/bugs/3110-no-type-ctor-or-field.typ deleted file mode 100644 index 61d65253..00000000 --- a/tests/typ/bugs/3110-no-type-ctor-or-field.typ +++ /dev/null @@ -1,15 +0,0 @@ -// Issue #3110: let the error message report the type name. -// https://github.com/typst/typst/issues/3110 -// Ref: false - ---- -// Error: 2-9 type content does not have a constructor -#content() - ---- -// Error: 6-12 type integer does not contain field `MAXVAL` -#int.MAXVAL - ---- -// Error: 6-18 type string does not contain field `from-unïcode` -#str.from-unïcode(97) diff --git a/tests/typ/bugs/3154-array-dict-mut-entry.typ b/tests/typ/bugs/3154-array-dict-mut-entry.typ deleted file mode 100644 index b5a52814..00000000 --- a/tests/typ/bugs/3154-array-dict-mut-entry.typ +++ /dev/null @@ -1,109 +0,0 @@ -// Issue #3154: Confusing errors from methods supposed to return a mutable entry -// https://github.com/typst/typst/issues/3154 -// Ref: false - ---- -#{ - let array = () - // Error: 3-16 array is empty - array.first() -} - ---- -#{ - let array = () - // Error: 3-16 array is empty - array.first() = 9 -} - ---- -#{ - let array = () - // Error: 3-15 array is empty - array.last() -} - ---- -#{ - let array = () - // Error: 3-15 array is empty - array.last() = 9 -} - ---- -#{ - let array = (1,) - // Error: 3-14 array index out of bounds (index: 1, len: 1) and no default value was specified - array.at(1) -} - ---- -#{ - let array = (1,) - test(array.at(1, default: 0), 0) -} - ---- -#{ - let array = (1,) - // Error: 3-14 array index out of bounds (index: 1, len: 1) - array.at(1) = 9 -} - ---- -#{ - let array = (1,) - // Error: 3-26 array index out of bounds (index: 1, len: 1) - array.at(1, default: 0) = 9 -} - ---- -#{ - let dict = (a: 1) - // Error: 3-15 dictionary does not contain key "b" and no default value was specified - dict.at("b") -} - ---- -#{ - let dict = (a: 1) - test(dict.at("b", default: 0), 0) -} - ---- -#{ - let dict = (a: 1) - // Error: 3-15 dictionary does not contain key "b" - // Hint: 3-15 use `insert` to add or update values - dict.at("b") = 9 -} - ---- -#{ - let dict = (a: 1) - // Error: 3-27 dictionary does not contain key "b" - // Hint: 3-27 use `insert` to add or update values - dict.at("b", default: 0) = 9 -} - ---- -#{ - let dict = (a: 1) - // Error: 8-9 dictionary does not contain key "b" - dict.b -} - ---- -#{ - let dict = (a: 1) - dict.b = 9 - test(dict, (a: 1, b: 9)) -} - ---- -#{ - let dict = (a: 1) - // Error: 3-9 dictionary does not contain key "b" - // Hint: 3-9 use `insert` to add or update values - dict.b += 9 -} diff --git a/tests/typ/bugs/3232-dict-wrong-keys.typ b/tests/typ/bugs/3232-dict-wrong-keys.typ deleted file mode 100644 index 61d9e8b8..00000000 --- a/tests/typ/bugs/3232-dict-wrong-keys.typ +++ /dev/null @@ -1,23 +0,0 @@ -// Issue #3232: Confusing "expected relative length or dictionary, found dictionary" -// https://github.com/typst/typst/issues/3232 -// Ref: false - ---- -// Error: 16-58 unexpected keys "unexpected" and "unexpected-too" -#block(outset: (unexpected: 0.5em, unexpected-too: 0.2em), [Hi]) - ---- -// Error: 14-56 unexpected keys "unexpected" and "unexpected-too" -#box(radius: (unexpected: 0.5em, unexpected-too: 0.5em), [Hi]) - ---- -// Error: 16-49 unexpected key "unexpected", valid keys are "left", "top", "right", "bottom", "x", "y", and "rest" -#block(outset: (unexpected: 0.2em, right: 0.5em), [Hi]) // The 1st key is unexpected - ---- -// Error: 14-50 unexpected key "unexpected", valid keys are "top-left", "top-right", "bottom-right", "bottom-left", "left", "top", "right", "bottom", and "rest" -#box(radius: (top-left: 0.5em, unexpected: 0.5em), [Hi]) // The 2nd key is unexpected - ---- -#block(outset: (:), [Hi]) // Ok -#box(radius: (:), [Hi]) // Ok diff --git a/tests/typ/bugs/3275-loop-errors.typ b/tests/typ/bugs/3275-loop-errors.typ deleted file mode 100644 index 9fdd2961..00000000 --- a/tests/typ/bugs/3275-loop-errors.typ +++ /dev/null @@ -1,67 +0,0 @@ -// Issue #3275: clearer errors for loops, https://github.com/typst/typst/issues/3275 -// Ref: false - ---- -// Normal variable. -#for x in (1, 2) {} -#for x in (a: 1, b: 2) {} -#for x in "foo" {} -#for x in bytes("😊") {} - ---- -// Placeholder. -#for _ in (1, 2) {} -#for _ in (a: 1, b: 2) {} -#for _ in "foo" {} -#for _ in bytes("😊") {} - ---- -// Destructuring. -#for (a,b,c) in (("a", 1, bytes(())), ("b", 2, bytes(""))) {} -#for (a, ..) in (("a", 1, bytes(())), ("b", 2, bytes(""))) {} -#for (k, v) in (a: 1, b: 2, c: 3) {} -#for (.., v) in (a: 1, b: 2, c: 3) {} - ---- -// Error: 11-17 cannot loop over content -#for x in [1, 2] {} - ---- -// Error: 11-25 cannot loop over arguments -#for _ in arguments("a") {} - ---- -// Error: 16-21 cannot loop over integer -#for (x, y) in 12306 {} - ---- -// Error: 16-22 cannot loop over content -#for (x, y) in [1, 2] {} - ---- -// Error: 6-12 cannot destructure values of string -#for (x, y) in "foo" {} - ---- -// Error: 6-12 cannot destructure string -#for (x, y) in ("foo", "bar") {} - ---- -// Error: 6-12 cannot destructure values of bytes -#for (x, y) in bytes("😊") {} - ---- -// Error: 6-12 cannot destructure bytes -#for (x, y) in (bytes((1,2)), bytes((1,2))) {} - ---- -// Error: 6-12 cannot destructure integer -#for (x, y) in (1, 2) {} - ---- -// Error: 10-11 not enough elements to destructure -#for (x, y) in ((1,), (2,)) {} - ---- -// Error: 6-12 too many elements to destructure -#for (x, y) in ((1,2,3), (4,5,6)) {} diff --git a/tests/typ/bugs/3363-json-large-number.typ b/tests/typ/bugs/3363-json-large-number.typ deleted file mode 100644 index 57d37f1b..00000000 --- a/tests/typ/bugs/3363-json-large-number.typ +++ /dev/null @@ -1,8 +0,0 @@ -// Big numbers (larger than what i64 can store) should just lose some precision -// but not overflow -// https://github.com/typst/typst/issues/3363 -// Ref: false - -#let bignum = json("/assets/data/big-number.json") - -#bignum
\ No newline at end of file diff --git a/tests/typ/bugs/3502-colon-space.typ b/tests/typ/bugs/3502-colon-space.typ deleted file mode 100644 index 35f38a9b..00000000 --- a/tests/typ/bugs/3502-colon-space.typ +++ /dev/null @@ -1,14 +0,0 @@ -// Test that a space after a named parameter is permissible. -// https://github.com/typst/typst/issues/3502 -// Ref: false - ---- -#let f( param : v ) = param -#test(f( param /* ok */ : 2 ), 2) - ---- -#let ( key : /* hi */ binding ) = ( key: "ok" ) -#test(binding, "ok") - ---- -#test(( key : "value" ).key, "value") diff --git a/tests/typ/bugs/3586-figure-caption-separator.typ b/tests/typ/bugs/3586-figure-caption-separator.typ deleted file mode 100644 index ee992c50..00000000 --- a/tests/typ/bugs/3586-figure-caption-separator.typ +++ /dev/null @@ -1,7 +0,0 @@ -// Test that figure caption separator is synthesized correctly. -// https://github.com/typst/typst/issues/3586 -// Ref: false - ---- -#show figure.caption: c => test(c.separator, [#": "]) -#figure(table[], caption: [This is a test caption]) diff --git a/tests/typ/bugs/3601-empty-raw.typ b/tests/typ/bugs/3601-empty-raw.typ deleted file mode 100644 index 3fb39aca..00000000 --- a/tests/typ/bugs/3601-empty-raw.typ +++ /dev/null @@ -1,7 +0,0 @@ -// Test that empty raw block with `typ` language doesn't cause a crash. -// https://github.com/typst/typst/issues/3601 -// Ref: false - ---- -```typ -``` diff --git a/tests/typ/bugs/3641-float-loop.typ b/tests/typ/bugs/3641-float-loop.typ deleted file mode 100644 index 4021fb4f..00000000 --- a/tests/typ/bugs/3641-float-loop.typ +++ /dev/null @@ -1,11 +0,0 @@ -// Flow layout should terminate! -// https://github.com/typst/typst/issues/3641 -// -// This is not yet ideal: The heading should not move to the second page, but -// that's a separate bug and not a regression. - ---- -#set page(height: 40pt) - -= Heading -#lorem(6) diff --git a/tests/typ/bugs/3650-italic-equation.typ b/tests/typ/bugs/3650-italic-equation.typ deleted file mode 100644 index c9b47543..00000000 --- a/tests/typ/bugs/3650-italic-equation.typ +++ /dev/null @@ -1,4 +0,0 @@ -_abc $sin(x) "abc"$_ \ -$italic(sin(x) "abc" #box[abc])$ \ -*abc $sin(x) "abc"$* \ -$bold(sin(x) "abc" #box[abc])$ \ diff --git a/tests/typ/bugs/3658-math-size.typ b/tests/typ/bugs/3658-math-size.typ deleted file mode 100644 index 63c020b2..00000000 --- a/tests/typ/bugs/3658-math-size.typ +++ /dev/null @@ -1,5 +0,0 @@ -// https://github.com/typst/typst/issues/3658 - ---- -$ #rect[$1/2$] $ -$#rect[$1/2$]$ diff --git a/tests/typ/bugs/3662-pdf-smartquotes.typ b/tests/typ/bugs/3662-pdf-smartquotes.typ deleted file mode 100644 index 36dc8a15..00000000 --- a/tests/typ/bugs/3662-pdf-smartquotes.typ +++ /dev/null @@ -1,12 +0,0 @@ -// Smart quotes were not appearing in the PDF outline, because they didn't -// implement `PlainText` -// https://github.com/typst/typst/issues/3662 - ---- -= It's "Unnormal Heading" -= It’s “Normal Heading” - -#set smartquote(enabled: false) -= It's "Unnormal Heading" -= It's 'single quotes' -= It’s “Normal Heading”
\ No newline at end of file diff --git a/tests/typ/bugs/3700-deformed-stroke.typ b/tests/typ/bugs/3700-deformed-stroke.typ deleted file mode 100644 index 7ca6ba6b..00000000 --- a/tests/typ/bugs/3700-deformed-stroke.typ +++ /dev/null @@ -1,11 +0,0 @@ -// Test shape fill & stroke for specific values that used to make the stroke -// deformed. -// https://github.com/typst/typst/issues/3700 - ---- -#rect( - radius: 1mm, - width: 100%, - height: 10pt, - stroke: (left: rgb("46b3c2") + 16.0mm), -)
\ No newline at end of file diff --git a/tests/typ/bugs/3841-tabs-in-raw-typ-code.typ b/tests/typ/bugs/3841-tabs-in-raw-typ-code.typ deleted file mode 100644 index db04fe3c..00000000 --- a/tests/typ/bugs/3841-tabs-in-raw-typ-code.typ +++ /dev/null @@ -1,20 +0,0 @@ -// Issue 3841 Tab chars are not rendered in raw blocks with lang: "typ(c)" -// https://github.com/typst/typst/issues/3841 - -#raw("#if true {\n\tf()\t// typ\n}", lang: "typ") - -#raw("if true {\n\tf()\t// typc\n}", lang: "typc") - -```typ -#if true { - // tabs around f() - f() // typ -} -``` - -```typc -if true { - // tabs around f() - f() // typc -} -``` diff --git a/tests/typ/bugs/870-image-rotation.typ b/tests/typ/bugs/870-image-rotation.typ deleted file mode 100644 index 5d7b5597..00000000 --- a/tests/typ/bugs/870-image-rotation.typ +++ /dev/null @@ -1,6 +0,0 @@ -// Ensure that EXIF rotation is applied. -// https://github.com/image-rs/image/issues/1045 - ---- -// File is from https://magnushoff.com/articles/jpeg-orientation/ -#image("/assets/images/f2t.jpg", width: 10pt) diff --git a/tests/typ/bugs/args-sink.typ b/tests/typ/bugs/args-sink.typ deleted file mode 100644 index 4f7492ac..00000000 --- a/tests/typ/bugs/args-sink.typ +++ /dev/null @@ -1,5 +0,0 @@ -// Test bugs with argument sinks. - ---- -#let foo(..body) = repr(body.pos()) -#foo(a: "1", b: "2", 1, 2, 3, 4, 5, 6) diff --git a/tests/typ/bugs/args-underscore.typ b/tests/typ/bugs/args-underscore.typ deleted file mode 100644 index ca3c0ff8..00000000 --- a/tests/typ/bugs/args-underscore.typ +++ /dev/null @@ -1,5 +0,0 @@ -// Test that lone underscore works. -// Ref: false - ---- -#test((1, 2, 3).map(_ => {}).len(), 3) diff --git a/tests/typ/bugs/bibliography-math.typ b/tests/typ/bugs/bibliography-math.typ deleted file mode 100644 index 3aab4b88..00000000 --- a/tests/typ/bugs/bibliography-math.typ +++ /dev/null @@ -1,4 +0,0 @@ -#set page(width: 200pt) - -@Zee04 -#bibliography("/assets/bib/works_too.bib", style: "mla") diff --git a/tests/typ/bugs/bidi-tofus.typ b/tests/typ/bugs/bidi-tofus.typ deleted file mode 100644 index 3b43b280..00000000 --- a/tests/typ/bugs/bidi-tofus.typ +++ /dev/null @@ -1,7 +0,0 @@ -// Test that shaping missing characters in both left-to-right and -// right-to-left directions does not cause a crash. - ---- -#"\u{590}\u{591}\u{592}\u{593}" - -#"\u{30000}\u{30001}\u{30002}\u{30003}" diff --git a/tests/typ/bugs/block-width-box.typ b/tests/typ/bugs/block-width-box.typ deleted file mode 100644 index a039bc66..00000000 --- a/tests/typ/bugs/block-width-box.typ +++ /dev/null @@ -1,6 +0,0 @@ -// Test box in 100% width block. - ---- -#block(width: 100%, fill: red, box("a box")) - -#block(width: 100%, fill: red, [#box("a box") #box()]) diff --git a/tests/typ/bugs/cite-locate.typ b/tests/typ/bugs/cite-locate.typ deleted file mode 100644 index 699bb085..00000000 --- a/tests/typ/bugs/cite-locate.typ +++ /dev/null @@ -1,23 +0,0 @@ -// Test citation in other introspection. - ---- -#set page(width: 180pt) -#set heading(numbering: "1") - -#outline( - title: [List of Figures], - target: figure.where(kind: image), -) - -#pagebreak() - -= Introduction <intro> -#figure( - rect[-- PIRATE --], - caption: [A pirate @arrgh in @intro], -) - -#context [Citation @distress on page #here().page()] - -#pagebreak() -#bibliography("/assets/bib/works.bib", style: "chicago-notes") diff --git a/tests/typ/bugs/cite-show-set.typ b/tests/typ/bugs/cite-show-set.typ deleted file mode 100644 index f476dd49..00000000 --- a/tests/typ/bugs/cite-show-set.typ +++ /dev/null @@ -1,9 +0,0 @@ -// Test show set rules on citations. - ---- -#show cite: set text(red) -A @netwok @arrgh. -B #cite(<netwok>) #cite(<arrgh>). - -#show bibliography: none -#bibliography("/assets/bib/works.bib") diff --git a/tests/typ/bugs/clamp-panic.typ b/tests/typ/bugs/clamp-panic.typ deleted file mode 100644 index 5f167c76..00000000 --- a/tests/typ/bugs/clamp-panic.typ +++ /dev/null @@ -1,3 +0,0 @@ -#set page(height: 20pt, margin: 0pt) -#v(22pt) -#block(fill: red, width: 100%, height: 10pt, radius: 4pt) diff --git a/tests/typ/bugs/columns-1.typ b/tests/typ/bugs/columns-1.typ deleted file mode 100644 index 96a4d0e5..00000000 --- a/tests/typ/bugs/columns-1.typ +++ /dev/null @@ -1,12 +0,0 @@ -// The well-known columns bug. - ---- -#set page(height: 70pt) - -Hallo -#columns(2)[ - = A - Text - = B - Text -] diff --git a/tests/typ/bugs/emoji-linebreak.typ b/tests/typ/bugs/emoji-linebreak.typ deleted file mode 100644 index 2f7e74e7..00000000 --- a/tests/typ/bugs/emoji-linebreak.typ +++ /dev/null @@ -1,6 +0,0 @@ -// Test that there are no linebreaks in composite emoji (issue #80). - ---- -#set page(width: 50pt, height: auto) -#h(99%) 🏳️🌈 -🏳️🌈 diff --git a/tests/typ/bugs/equation-numbering-reference.typ b/tests/typ/bugs/equation-numbering-reference.typ deleted file mode 100644 index 3423f022..00000000 --- a/tests/typ/bugs/equation-numbering-reference.typ +++ /dev/null @@ -1,15 +0,0 @@ -// In this bug, the hint and error messages for an equation -// being reference mentioned that it was a "heading" and was -// lacking the proper path. -// Ref: false - ---- -#set page(height: 70pt) - -$ - Delta = b^2 - 4 a c -$ <quadratic> - -// Error: 14-24 cannot reference equation without numbering -// Hint: 14-24 you can enable equation numbering with `#set math.equation(numbering: "1.")` -Looks at the @quadratic formula.
\ No newline at end of file diff --git a/tests/typ/bugs/flow-1.typ b/tests/typ/bugs/flow-1.typ deleted file mode 100644 index 425a0ce8..00000000 --- a/tests/typ/bugs/flow-1.typ +++ /dev/null @@ -1,11 +0,0 @@ -// In this bug, the first line of the second paragraph was on its page alone an -// the rest moved down. The reason was that the second block resulted in -// overlarge frames because the region wasn't finished properly. - ---- -#set page(height: 70pt) -#block[This file tests a bug where an almost empty page occurs.] -#block[ - The text in this second block was torn apart and split up for - some reason beyond my knowledge. -] diff --git a/tests/typ/bugs/flow-2.typ b/tests/typ/bugs/flow-2.typ deleted file mode 100644 index 5ffffd58..00000000 --- a/tests/typ/bugs/flow-2.typ +++ /dev/null @@ -1,10 +0,0 @@ -// In this bug, the first part of the paragraph moved down to the second page -// because trailing leading wasn't trimmed, resulting in an overlarge frame. - ---- -#set page(height: 60pt) -#v(19pt) -#block[ - But, soft! what light through yonder window breaks? - It is the east, and Juliet is the sun. -] diff --git a/tests/typ/bugs/flow-3.typ b/tests/typ/bugs/flow-3.typ deleted file mode 100644 index 71af1914..00000000 --- a/tests/typ/bugs/flow-3.typ +++ /dev/null @@ -1,12 +0,0 @@ -// In this bug, there was a bit of space below the heading because weak spacing -// directly before a layout-induced column or page break wasn't trimmed. - ---- -#set page(height: 60pt) -#rect(inset: 0pt, columns(2)[ - Text - #v(12pt) - Hi - #v(10pt, weak: true) - At column break. -]) diff --git a/tests/typ/bugs/flow-4.typ b/tests/typ/bugs/flow-4.typ deleted file mode 100644 index f49873f5..00000000 --- a/tests/typ/bugs/flow-4.typ +++ /dev/null @@ -1,5 +0,0 @@ -// In this bug, a frame intended for the second region ended up in the first. - ---- -#set page(height: 105pt) -#block(lorem(20)) diff --git a/tests/typ/bugs/flow-5.typ b/tests/typ/bugs/flow-5.typ deleted file mode 100644 index 5e580b9e..00000000 --- a/tests/typ/bugs/flow-5.typ +++ /dev/null @@ -1,13 +0,0 @@ -// This bug caused an index-out-of-bounds panic when layouting paragraphs needed -// multiple reorderings. - ---- -#set page(height: 200pt) -#lorem(30) - -#figure(placement: auto, block(height: 100%)) - -#lorem(10) - -#lorem(10) - diff --git a/tests/typ/bugs/fold-vector.typ b/tests/typ/bugs/fold-vector.typ deleted file mode 100644 index 5d57ad33..00000000 --- a/tests/typ/bugs/fold-vector.typ +++ /dev/null @@ -1,20 +0,0 @@ -// Test fold order of vectors. - ---- -#set text(features: (liga: 1)) -#set text(features: (liga: 0)) -fi - ---- -#underline(stroke: aqua + 4pt)[ - #underline[Hello] -] - ---- -#let c = counter("mycounter") -#c.update(1) -#locate(loc => [ - #c.update(2) - #c.at(loc) \ - Second: #locate(loc => c.at(loc)) -]) diff --git a/tests/typ/bugs/footnote-keep-multiple.typ b/tests/typ/bugs/footnote-keep-multiple.typ deleted file mode 100644 index e4efe3ce..00000000 --- a/tests/typ/bugs/footnote-keep-multiple.typ +++ /dev/null @@ -1,10 +0,0 @@ -// Test that the logic that keeps footnote entry together with -// their markers also works for multiple footnotes in a single -// line or frame (here, there are two lines, but they are one -// unit due to orphan prevention). - ---- -#set page(height: 100pt) -#v(40pt) -A #footnote[a] \ -B #footnote[b] diff --git a/tests/typ/bugs/footnote-list.typ b/tests/typ/bugs/footnote-list.typ deleted file mode 100644 index ceece0ca..00000000 --- a/tests/typ/bugs/footnote-list.typ +++ /dev/null @@ -1,11 +0,0 @@ -// Test that footnotes in lists do not produce extraneous page breaks. The list -// layout itself does not currently react to the footnotes layout, weakening the -// "footnote and its entry are on the same page" invariant somewhat, but at -// least there shouldn't be extra page breaks. - ---- -#set page(height: 100pt) -#block(height: 50pt, width: 100%, fill: aqua) - -- #footnote[1] -- #footnote[2] diff --git a/tests/typ/bugs/gradient-cmyk-encode.typ b/tests/typ/bugs/gradient-cmyk-encode.typ deleted file mode 100644 index 5e0b58dc..00000000 --- a/tests/typ/bugs/gradient-cmyk-encode.typ +++ /dev/null @@ -1,27 +0,0 @@ -// Test that CMYK works on gradients - ---- -#set page(margin: 0pt, width: 200pt, height: auto) - -#let violet = cmyk(75%, 80%, 0%, 0%) -#let blue = cmyk(75%, 30%, 0%, 0%) - -#rect( - width: 100%, - height: 30pt, - fill: gradient.linear(violet, blue) -) - -#rect( - width: 100%, - height: 30pt, - fill: gradient.linear(rgb(violet), rgb(blue)) -) - -// In PDF format, this gradient can look different from the others. -// This is because PDF readers do weird things with CMYK. -#rect( - width: 100%, - height: 30pt, - fill: gradient.linear(violet, blue, space: cmyk) -) diff --git a/tests/typ/bugs/grid-1.typ b/tests/typ/bugs/grid-1.typ deleted file mode 100644 index c583cfe5..00000000 --- a/tests/typ/bugs/grid-1.typ +++ /dev/null @@ -1,16 +0,0 @@ -// Test that grid base for auto rows makes sense. - ---- -#set page(height: 150pt) -#table( - columns: (1.5cm, auto), - rows: (auto, auto), - rect(width: 100%, fill: red), - rect(width: 100%, fill: blue), - rect(width: 100%, height: 50%, fill: green), -) - ---- -#rect(width: 100%, height: 1em) -- #rect(width: 100%, height: 1em) - - #rect(width: 100%, height: 1em) diff --git a/tests/typ/bugs/grid-2.typ b/tests/typ/bugs/grid-2.typ deleted file mode 100644 index b7528b7b..00000000 --- a/tests/typ/bugs/grid-2.typ +++ /dev/null @@ -1,20 +0,0 @@ -// Grid now skips a remaining region when one of the cells -// doesn't fit into it at all. - ---- -#set page(height: 100pt) -#grid( - columns: (2cm, auto), - rows: (auto, auto), - rect(width: 100%, fill: red), - rect(width: 100%, fill: blue), - rect(width: 100%, height: 80%, fill: green), - [hello \ darkness #parbreak() my \ old \ friend \ I], - rect(width: 100%, height: 20%, fill: blue), - polygon(fill: red, (0%, 0%), (100%, 0%), (100%, 20%)) -) - ---- -#set page(height: 60pt) -#lorem(5) -- #lorem(5) diff --git a/tests/typ/bugs/grid-3.typ b/tests/typ/bugs/grid-3.typ deleted file mode 100644 index 19317c50..00000000 --- a/tests/typ/bugs/grid-3.typ +++ /dev/null @@ -1,8 +0,0 @@ -// Ensure that the list does not jump to the third page. - ---- -#set page(height: 70pt) -#v(40pt) -The following: -+ A -+ B diff --git a/tests/typ/bugs/grid-4.typ b/tests/typ/bugs/grid-4.typ deleted file mode 100644 index 691bf877..00000000 --- a/tests/typ/bugs/grid-4.typ +++ /dev/null @@ -1,17 +0,0 @@ -// Ensure gutter rows at the top or bottom of a region are skipped. - ---- -#set page(height: 10em) - -#table( - row-gutter: 1.5em, - inset: 0pt, - rows: (1fr, auto), - [a], - [], - [], - [f], - [e\ e], - [], - [a] -) diff --git a/tests/typ/bugs/hide-meta.typ b/tests/typ/bugs/hide-meta.typ deleted file mode 100644 index 8d2c7cb6..00000000 --- a/tests/typ/bugs/hide-meta.typ +++ /dev/null @@ -1,24 +0,0 @@ -// Test that metadata of hidden stuff stays available. - ---- -#set cite(style: "chicago-notes") - -A pirate. @arrgh \ -#set text(2pt) -#hide[ - A @arrgh pirate. - #bibliography("/assets/bib/works.bib") -] - ---- -#set text(8pt) -#outline() -#set text(2pt) -#hide(block(grid( - [= A], - [= B], - block(grid( - [= C], - [= D], - )) -))) diff --git a/tests/typ/bugs/int-constructor.typ b/tests/typ/bugs/int-constructor.typ deleted file mode 100644 index 0bdce612..00000000 --- a/tests/typ/bugs/int-constructor.typ +++ /dev/null @@ -1,7 +0,0 @@ -// Test that integer -> integer conversion doesn't do a roundtrip through float. -// Ref: false - ---- -#let x = 9223372036854775800 -#test(type(x), int) -#test(int(x), x) diff --git a/tests/typ/bugs/justify-hanging-indent.typ b/tests/typ/bugs/justify-hanging-indent.typ deleted file mode 100644 index 511aa172..00000000 --- a/tests/typ/bugs/justify-hanging-indent.typ +++ /dev/null @@ -1,6 +0,0 @@ -// Test that combination of justification and hanging indent doesn't result in -// an underfull first line. - ---- -#set par(hanging-indent: 2.5cm, justify: true) -#lorem(5) diff --git a/tests/typ/bugs/label-fields-dict.typ b/tests/typ/bugs/label-fields-dict.typ deleted file mode 100644 index 05c7006a..00000000 --- a/tests/typ/bugs/label-fields-dict.typ +++ /dev/null @@ -1,31 +0,0 @@ -// Tests whether the label is accessible through the has, field, -// and fields accessors -// Ref: false - ---- -// Test whether the label is accessible through the has method -#show heading: it => { - assert(it.has("label")) - it -} - -= Hello, world! <my_label> - ---- -// Test whether the label is accessible through the field method -#show heading: it => { - assert(str(it.label) == "my_label") - it -} - -= Hello, world! <my_label> - ---- -// Test whether the label is accessible through the fields method -#show heading: it => { - assert("label" in it.fields()) - assert(str(it.fields().label) == "my_label") - it -} - -= Hello, world! <my_label> diff --git a/tests/typ/bugs/layout-infinite-lengths.typ b/tests/typ/bugs/layout-infinite-lengths.typ deleted file mode 100644 index 7fbc6216..00000000 --- a/tests/typ/bugs/layout-infinite-lengths.typ +++ /dev/null @@ -1,25 +0,0 @@ -// Test that passing infinite lengths to drawing primitives does not crash Typst. - ---- -#set page(width: auto, height: auto) - -// Error: 58-59 cannot expand into infinite width -#layout(size => grid(columns: (size.width, size.height))[a][b][c][d]) - ---- -#set page(width: auto, height: auto) - -// Error: 17-66 cannot create grid with infinite height -#layout(size => grid(rows: (size.width, size.height))[a][b][c][d]) - ---- -#set page(width: auto, height: auto) - -// Error: 17-41 cannot create line with infinite length -#layout(size => line(length: size.width)) - ---- -#set page(width: auto, height: auto) - -// Error: 17-54 cannot create polygon with infinite size -#layout(size => polygon((0pt,0pt), (0pt, size.width))) diff --git a/tests/typ/bugs/line-align.typ b/tests/typ/bugs/line-align.typ deleted file mode 100644 index 0518eaaa..00000000 --- a/tests/typ/bugs/line-align.typ +++ /dev/null @@ -1,5 +0,0 @@ -// Test right-aligning a line and a rectangle. - ---- -#align(right, line(length: 30%)) -#align(right, rect()) diff --git a/tests/typ/bugs/linebreak-no-justifiables.typ b/tests/typ/bugs/linebreak-no-justifiables.typ deleted file mode 100644 index ab1b2732..00000000 --- a/tests/typ/bugs/linebreak-no-justifiables.typ +++ /dev/null @@ -1,5 +0,0 @@ -// Test breaking a line without justifiables. - ---- -#set par(justify: true) -#block(width: 1cm, fill: aqua, lorem(2)) diff --git a/tests/typ/bugs/mat-aug-color.typ b/tests/typ/bugs/mat-aug-color.typ deleted file mode 100644 index c2e617d6..00000000 --- a/tests/typ/bugs/mat-aug-color.typ +++ /dev/null @@ -1,9 +0,0 @@ -// https://github.com/typst/typst/issues/2268 -// The augment line should be of the same color as the text -#set text( - font: "New Computer Modern", - lang: "en", - fill: yellow, -) - -$mat(augment: #1, M, v) arrow.r.squiggly mat(augment: #1, R, b)$ diff --git a/tests/typ/bugs/math-eval.typ b/tests/typ/bugs/math-eval.typ deleted file mode 100644 index 31450b8d..00000000 --- a/tests/typ/bugs/math-eval.typ +++ /dev/null @@ -1,5 +0,0 @@ -// Evaluating a math expr should renders the same as an equation - -#eval(mode: "math", "f(a) = cases(a + b\, space space x >= 3,a + b\, space space x = 5)") - -$f(a) = cases(a + b\, space space x >= 3,a + b\, space space x = 5)$ diff --git a/tests/typ/bugs/math-number-spacing.typ b/tests/typ/bugs/math-number-spacing.typ deleted file mode 100644 index 9450caca..00000000 --- a/tests/typ/bugs/math-number-spacing.typ +++ /dev/null @@ -1,9 +0,0 @@ -// Test spacing after numbers in math. - ---- -$ -10degree \ -10 degree \ -10.1degree \ -10.1 degree -$ diff --git a/tests/typ/bugs/math-realize.typ b/tests/typ/bugs/math-realize.typ deleted file mode 100644 index 10d8b78e..00000000 --- a/tests/typ/bugs/math-realize.typ +++ /dev/null @@ -1,47 +0,0 @@ -// Test that content in math can be realized without breaking -// nested equations. - ---- -#let my = $pi$ -#let f1 = box(baseline: 10pt, [f]) -#let f2 = context f1 -#show math.vec: [nope] - -$ pi a $ -$ my a $ -$ 1 + sqrt(x/2) + sqrt(#hide($x/2$)) $ -$ a x #link("url", $+ b$) $ -$ f f1 f2 $ -$ vec(1,2) * 2 $ - ---- -$ x^2 #hide[$(>= phi.alt) union y^2 0$] z^2 $ -Hello #hide[there $x$] -and #hide[$ f(x) := x^2 $] - ---- -// Test equations can embed equation pieces built by functions -#let foo(v1, v2) = { - // Return an equation piece that would've been rendered in - // inline style if the piece is not embedded - $v1 v2^2$ -} -#let bar(v1, v2) = { - // Return an equation piece that would've been rendered in - // block style if the piece is not embedded - $ v1 v2^2 $ -} -#let baz(..sink) = { - // Return an equation piece built by joining arrays - sink.pos().map(x => $hat(#x)$).join(sym.and) -} - -Inline $2 foo(alpha, (M+foo(a, b)))$. - -Inline $2 bar(alpha, (M+foo(a, b)))$. - -Inline $2 baz(x,y,baz(u, v))$. - -$ 2 foo(alpha, (M+foo(a, b))) $ -$ 2 bar(alpha, (M+foo(a, b))) $ -$ 2 baz(x,y,baz(u, v)) $ diff --git a/tests/typ/bugs/math-shift.typ b/tests/typ/bugs/math-shift.typ deleted file mode 100644 index 4a833e31..00000000 --- a/tests/typ/bugs/math-shift.typ +++ /dev/null @@ -1,5 +0,0 @@ -// https://github.com/typst/typst/issues/2214 -// The math content should also be affected by the TextElem baseline. - -hello #text(baseline: -5pt)[123 #sym.WW\orld]\ -hello #text(baseline: -5pt)[$123 WW#text[or]$ld]\ diff --git a/tests/typ/bugs/math-text-break.typ b/tests/typ/bugs/math-text-break.typ deleted file mode 100644 index a8aa1d0a..00000000 --- a/tests/typ/bugs/math-text-break.typ +++ /dev/null @@ -1,4 +0,0 @@ -// Test text with linebreaks in math. - ---- -$ x := "a\nb\nc\nd\ne" $ diff --git a/tests/typ/bugs/measure-image.typ b/tests/typ/bugs/measure-image.typ deleted file mode 100644 index bd8703b3..00000000 --- a/tests/typ/bugs/measure-image.typ +++ /dev/null @@ -1,8 +0,0 @@ -// Test that image measurement doesn't turn `inf / some-value` into 0pt. -// Ref: false - ---- -#context { - let size = measure(image("/assets/images/tiger.jpg")) - test(size, (width: 1024pt, height: 670pt)) -} diff --git a/tests/typ/bugs/new-cm-svg.typ b/tests/typ/bugs/new-cm-svg.typ deleted file mode 100644 index eeafcbbd..00000000 --- a/tests/typ/bugs/new-cm-svg.typ +++ /dev/null @@ -1,2 +0,0 @@ -#set text(font: "New Computer Modern") -#image("/assets/images/diagram.svg") diff --git a/tests/typ/bugs/newline-mode.typ b/tests/typ/bugs/newline-mode.typ deleted file mode 100644 index 04333cc5..00000000 --- a/tests/typ/bugs/newline-mode.typ +++ /dev/null @@ -1,84 +0,0 @@ -// Test newline continuations. - ---- -#{ - "hello" - .clusters() - if false { - - } - else { - ("1", "2") - } -} - ---- -#"hello" - .codepoints() - -#if false { - -} -else { - ("1", "2") -} - ---- -// Ref: false -#test({ - "hi 1" - - .clusters() -}, ("h", "i", " ", "1")) - ---- -// Ref: false -#test({ - "hi 2"// comment - .clusters() -}, ("h", "i", " ", "2")) - ---- -// Ref: false -#test({ - "hi 3"/* comment */ - .clusters() -}, ("h", "i", " ", "3")) - ---- -// Ref: false -#test({ - "hi 4" - // comment - .clusters() -}, ("h", "i", " ", "4")) - ---- -// Ref: false -#test({ - "hi 5" - /*comment*/.clusters() -}, ("h", "i", " ", "5")) - ---- -// Ref: false -#test({ - "hi 6" - // comment - - - /* comment */ - .clusters() -}, ("h", "i", " ", "6")) - ---- -// Ref: false -#test({ - let foo(x) = { - if x < 0 { "negative" } - // comment - else { "non-negative" } - } - - foo(1) -}, "non-negative") diff --git a/tests/typ/bugs/pagebreak-bibliography.typ b/tests/typ/bugs/pagebreak-bibliography.typ deleted file mode 100644 index 257043a3..00000000 --- a/tests/typ/bugs/pagebreak-bibliography.typ +++ /dev/null @@ -1,5 +0,0 @@ -// Test weak pagebreak before bibliography. - ---- -#pagebreak(weak: true) -#bibliography("/assets/bib/works.bib") diff --git a/tests/typ/bugs/pagebreak-numbering.typ b/tests/typ/bugs/pagebreak-numbering.typ deleted file mode 100644 index a9fae3e4..00000000 --- a/tests/typ/bugs/pagebreak-numbering.typ +++ /dev/null @@ -1,12 +0,0 @@ -// https://github.com/typst/typst/issues/2095 -// The empty page 2 should not have a page number - -#set page(numbering: none) -This and next page should not be numbered - -#pagebreak(weak: true, to: "odd") - -#set page(numbering: "1") -#counter(page).update(1) - -This page should diff --git a/tests/typ/bugs/pagebreak-set-style.typ b/tests/typ/bugs/pagebreak-set-style.typ deleted file mode 100644 index 1ac24652..00000000 --- a/tests/typ/bugs/pagebreak-set-style.typ +++ /dev/null @@ -1,12 +0,0 @@ -// https://github.com/typst/typst/issues/2162 -// The styles should not be applied to the pagebreak empty page, -// it should only be applied after that. - -#pagebreak(to: "even") // We should now skip to page 2 - -Some text on page 2 - -#pagebreak(to: "even") // We should now skip to page 4 - -#set page(fill: orange) // This sets the color of the page starting from page 4 -Some text on page 4 diff --git a/tests/typ/bugs/parameter-pattern.typ b/tests/typ/bugs/parameter-pattern.typ deleted file mode 100644 index 31b07f2c..00000000 --- a/tests/typ/bugs/parameter-pattern.typ +++ /dev/null @@ -1,5 +0,0 @@ -// Test that underscore works in parameter patterns. -// Ref: false - ---- -#test((1, 2, 3).zip((1, 2, 3)).map(((_, x)) => x), (1, 2, 3)) diff --git a/tests/typ/bugs/parenthesized.typ b/tests/typ/bugs/parenthesized.typ deleted file mode 100644 index f8f3190f..00000000 --- a/tests/typ/bugs/parenthesized.typ +++ /dev/null @@ -1,98 +0,0 @@ -// Ref: false -// Test bugs related to destructuring and parenthesized parsing. - ---- -// https://github.com/typst/typst/issues/1338 -#let foo = "foo" -#let bar = "bar" -// Error: 8-9 expected expression, found underscore -// Error: 16-17 expected expression, found underscore -#(foo: _, bar: _) - ---- -// https://github.com/typst/typst/issues/1342 -// Error: 5-8 expected named or keyed pair, found identifier -// Error: 10-13 expected named or keyed pair, found identifier -#(: foo, bar) - ---- -// https://github.com/typst/typst/issues/1351 -// Error: 17-22 expected pattern, found string -#let foo((test: "bar")) = {} - ---- -// https://github.com/typst/typst/issues/3014 -// Error: 8-17 expected expression, found named pair -#(box, fill: red) - ---- -// https://github.com/typst/typst/issues/3144 -#let f(a: 10) = a(1) + 1 -#test(f(a: _ => 5), 6) - ---- -// Error: 17-20 missing argument: pattern parameter -#let f(a: 10) = a() + 1 -#f(a: _ => 5) - ---- -// This wasn't allowed. -#let ((x)) = 1 -#test(x, 1) - ---- -// This also wasn't allowed. -#let ((a, b)) = (1, 2) -#test(a, 1) -#test(b, 2) - ---- -// This was unintentionally allowed ... -// Error: 9 expected equals sign -#let (a) - ---- -// ... where this wasn't. -// Error: 12 expected equals sign -#let (a, b) - ---- -// This wasn't allowed before the bug fix ... -#let f(..) = {} -#f(arg: 1) - ---- -// ... but this was. -#let f(..x) = {} -#f(arg: 1) - ---- -// Here, `best` was accessed as a variable, where it shouldn't have. -#{ - (best: _) = (best: "brr") -} - ---- -// Same here. -#{ - let array = (1, 2, 3, 4) - (test: array.at(1), best: _) = (test: "baz", best: "brr") - test(array, (1, "baz", 3, 4)) -} - ---- -// Here, `a` is not duplicate, where it was previously identified as one. -#let f((a: b), (c,), a) = (a, b, c) -#test(f((a: 1), (2,), 3), (3, 1, 2)) - ---- -// Ensure that we can't have non-atomic closures. -#let x = 1 -#let c = [#(x) => (1, 2)] -#test(c.children.last(), [(1, 2)])) - ---- -// Ensure that we can't have non-atomic destructuring. -#let x = 1 -#let c = [#() = ()] -#test(c.children.last(), [()]) diff --git a/tests/typ/bugs/place-base.typ b/tests/typ/bugs/place-base.typ deleted file mode 100644 index 4a0bd029..00000000 --- a/tests/typ/bugs/place-base.typ +++ /dev/null @@ -1,7 +0,0 @@ -// Test that placement is relative to container and not itself. - ---- -#set page(height: 80pt, margin: 0pt) -#place(right, dx: -70%, dy: 20%, [First]) -#place(left, dx: 20%, dy: 60%, [Second]) -#place(center + horizon, dx: 25%, dy: 25%, [Third]) diff --git a/tests/typ/bugs/place-pagebreak.typ b/tests/typ/bugs/place-pagebreak.typ deleted file mode 100644 index bc04af1a..00000000 --- a/tests/typ/bugs/place-pagebreak.typ +++ /dev/null @@ -1,7 +0,0 @@ -// Test placing on an already full page. -// It shouldn't result in a page break. - ---- -#set page(height: 40pt) -#block(height: 100%) -#place(bottom + right)[Hello world] diff --git a/tests/typ/bugs/place-spacing.typ b/tests/typ/bugs/place-spacing.typ deleted file mode 100644 index 4d7b5fe3..00000000 --- a/tests/typ/bugs/place-spacing.typ +++ /dev/null @@ -1,15 +0,0 @@ -// Test that placed elements don't add extra block spacing. - ---- -#show figure: set block(spacing: 4em) - -Paragraph before float. -#figure(rect(), placement: bottom) -Paragraph after float. - ---- -#show place: set block(spacing: 4em) - -Paragraph before place. -#place(rect()) -Paragraph after place. diff --git a/tests/typ/bugs/raw-color-overwrite.typ b/tests/typ/bugs/raw-color-overwrite.typ deleted file mode 100644 index ec306ef1..00000000 --- a/tests/typ/bugs/raw-color-overwrite.typ +++ /dev/null @@ -1,13 +0,0 @@ -// Test that the color of a raw block is not overwritten - ---- - -#show raw: set text(fill: blue) - -`Hello, World!` - -```rs -fn main() { - println!("Hello, World!"); -} -```
\ No newline at end of file diff --git a/tests/typ/bugs/smartquotes-in-outline.typ b/tests/typ/bugs/smartquotes-in-outline.typ deleted file mode 100644 index 1ecfcdc4..00000000 --- a/tests/typ/bugs/smartquotes-in-outline.typ +++ /dev/null @@ -1,4 +0,0 @@ -#set page(width: 15em) -#outline() - -= "This" "is" "a" "test" diff --git a/tests/typ/bugs/smartquotes-on-newline.typ b/tests/typ/bugs/smartquotes-on-newline.typ deleted file mode 100644 index 3180350e..00000000 --- a/tests/typ/bugs/smartquotes-on-newline.typ +++ /dev/null @@ -1,7 +0,0 @@ -// Test that smart quotes are inferred correctly across newlines. - ---- -"test"#linebreak()"test" - -"test"\ -"test" diff --git a/tests/typ/bugs/spacing-behaviour.typ b/tests/typ/bugs/spacing-behaviour.typ deleted file mode 100644 index a2a30b8a..00000000 --- a/tests/typ/bugs/spacing-behaviour.typ +++ /dev/null @@ -1,9 +0,0 @@ -// Test that metadata after spacing does not force a new paragraph. - ---- -#{ - h(1em) - counter(heading).update(4) - [Hello ] - counter(heading).display() -} diff --git a/tests/typ/bugs/square-base.typ b/tests/typ/bugs/square-base.typ deleted file mode 100644 index d8339c1a..00000000 --- a/tests/typ/bugs/square-base.typ +++ /dev/null @@ -1,5 +0,0 @@ -// Test that square sets correct base for its content. - ---- -#set page(height: 80pt) -#square(width: 40%, rect(width: 60%, height: 80%)) diff --git a/tests/typ/bugs/subelement-panic.typ b/tests/typ/bugs/subelement-panic.typ deleted file mode 100644 index fcad83bc..00000000 --- a/tests/typ/bugs/subelement-panic.typ +++ /dev/null @@ -1,40 +0,0 @@ -// Test that figure captions don't cause panics. -// Ref: false - ---- -// #2530 -#figure(caption: [test])[].caption - ---- -// #2165 -#figure.caption[] - ---- -// #2328 -// Error: 4-43 footnote entry must have a location -// Hint: 4-43 try using a query or a show rule to customize the footnote instead -HI#footnote.entry(clearance: 2.5em)[There] - ---- -// Enum item (pre-emptive) -#enum.item(none)[Hello] -#enum.item(17)[Hello] - ---- -// List item (pre-emptive) -#list.item[Hello] - ---- -// Term item (pre-emptive) -#terms.item[Hello][World!] - ---- -// Outline entry (pre-emptive) -// Error: 2-48 cannot outline text -#outline.entry(1, [Hello], [World!], none, [1]) - ---- -// Outline entry (pre-emptive, improved error) -// Error: 2-55 heading must have a location -// Hint: 2-55 try using a query or a show rule to customize the outline.entry instead -#outline.entry(1, heading[Hello], [World!], none, [1]) diff --git a/tests/typ/bugs/table-lines.typ b/tests/typ/bugs/table-lines.typ deleted file mode 100644 index 7e954012..00000000 --- a/tests/typ/bugs/table-lines.typ +++ /dev/null @@ -1,10 +0,0 @@ -// Ensure no empty lines before a table that doesn't fit into the first page. - ---- -#set page(height: 50pt) - -Hello -#table( - columns: 4, - [1], [2], [3], [4] -) diff --git a/tests/typ/bugs/table-row-missing.typ b/tests/typ/bugs/table-row-missing.typ deleted file mode 100644 index d72305ba..00000000 --- a/tests/typ/bugs/table-row-missing.typ +++ /dev/null @@ -1,8 +0,0 @@ -// Test that a table row isn't wrongly treated like a gutter row. - ---- -#set page(height: 70pt) -#table( - rows: 16pt, - ..range(6).map(str).flatten(), -) diff --git a/tests/typ/coma.typ b/tests/typ/coma.typ deleted file mode 100644 index 8ca08ddb..00000000 --- a/tests/typ/coma.typ +++ /dev/null @@ -1,24 +0,0 @@ -#set page(width: 450pt, margin: 1cm) - -*Technische Universität Berlin* #h(1fr) *WiSe 2019/2020* \ -*Fakultät II, Institut for Mathematik* #h(1fr) Woche 3 \ -Sekretariat MA \ -Dr. Max Mustermann \ -Ola Nordmann, John Doe - -#v(3mm) -#align(center)[ - #set par(leading: 3mm) - #text(1.2em)[*3. Übungsblatt Computerorientierte Mathematik II*] \ - *Abgabe: 03.05.2019* (bis 10:10 Uhr in MA 001) \ - *Alle Antworten sind zu beweisen.* -] - -*1. Aufgabe* #h(1fr) (1 + 1 + 2 Punkte) - -Ein _Binärbaum_ ist ein Wurzelbaum, in dem jeder Knoten ≤ 2 Kinder hat. -Die Tiefe eines Knotens _v_ ist die Länge des eindeutigen Weges von der Wurzel -zu _v_, und die Höhe von _v_ ist die Länge eines längsten (absteigenden) Weges -von _v_ zu einem Blatt. Die Höhe des Baumes ist die Höhe der Wurzel. - -#align(center, image("/assets/images/graph.png", width: 75%)) diff --git a/tests/typ/compiler/array.typ b/tests/typ/compiler/array.typ deleted file mode 100644 index 4a1948ff..00000000 --- a/tests/typ/compiler/array.typ +++ /dev/null @@ -1,370 +0,0 @@ -// Test arrays. -// Ref: false - ---- -// Ref: true - -#set page(width: 150pt) - -// Empty. -#() - -// Not an array, just a parenthesized expression. -#(1) - -// One item and trailing comma. -#(-1,) - -// No trailing comma. -#(true, false) - -// Multiple lines and items and trailing comma. -#("1" - , rgb("002") - ,) - ---- -// Test the `len` method. -#test(().len(), 0) -#test(("A", "B", "C").len(), 3) - ---- -// Test lvalue and rvalue access. -#{ - let array = (1, 2) - array.at(1) += 5 + array.at(0) - test(array, (1, 8)) -} - ---- -// Test different lvalue method. -#{ - let array = (1, 2, 3) - array.first() = 7 - array.at(1) *= 8 - test(array, (7, 16, 3)) -} - ---- -// Test rvalue out of bounds. -// Error: 2-17 array index out of bounds (index: 5, len: 3) and no default value was specified -#(1, 2, 3).at(5) - ---- -// Test lvalue out of bounds. -#{ - let array = (1, 2, 3) - // Error: 3-14 array index out of bounds (index: 3, len: 3) - array.at(3) = 5 -} - ---- -// Test default value. -#test((1, 2, 3).at(2, default: 5), 3) -#test((1, 2, 3).at(3, default: 5), 5) - ---- -// Test remove with default value. - -#{ - let array = (1, 2, 3) - test(array.remove(2, default: 5), 3) -} - -#{ - let array = (1, 2, 3) - test(array.remove(3, default: 5), 5) -} - ---- -// Test bad lvalue. -// Error: 2:3-2:14 cannot mutate a temporary value -#let array = (1, 2, 3) -#(array.len() = 4) - ---- -// Test bad lvalue. -// Error: 2:9-2:13 type array has no method `yolo` -#let array = (1, 2, 3) -#(array.yolo() = 4) - ---- -// Test negative indices. -#{ - let array = (1, 2, 3, 4) - test(array.at(0), 1) - test(array.at(-1), 4) - test(array.at(-2), 3) - test(array.at(-3), 2) - test(array.at(-4), 1) -} - ---- -// The the `first` and `last` methods. -#test((1,).first(), 1) -#test((2,).last(), 2) -#test((1, 2, 3).first(), 1) -#test((1, 2, 3).last(), 3) - ---- -// Error: 2-12 array is empty -#().first() - ---- -// Error: 2-11 array is empty -#().last() - ---- -// Test the `push` and `pop` methods. -#{ - let tasks = (a: (1, 2, 3), b: (4, 5, 6)) - test(tasks.at("a").pop(), 3) - tasks.b.push(7) - test(tasks.a, (1, 2)) - test(tasks.at("b"), (4, 5, 6, 7)) -} - ---- -// Test the `insert` and `remove` methods. -#{ - let array = (0, 1, 2, 4, 5) - array.insert(3, 3) - test(array, range(6)) - array.remove(1) - test(array, (0, 2, 3, 4, 5)) -} - ---- -// Error: 2:2-2:18 missing argument: index -#let numbers = () -#numbers.insert() - ---- -// Test the `slice` method. -#test((1, 2, 3, 4).slice(2), (3, 4)) -#test(range(10).slice(2, 6), (2, 3, 4, 5)) -#test(range(10).slice(4, count: 3), (4, 5, 6)) -#test(range(10).slice(-5, count: 2), (5, 6)) -#test((1, 2, 3).slice(2, -2), ()) -#test((1, 2, 3).slice(-2, 2), (2,)) -#test((1, 2, 3).slice(-3, 2), (1, 2)) -#test("ABCD".split("").slice(1, -1).join("-"), "A-B-C-D") - ---- -// Error: 2-30 array index out of bounds (index: 12, len: 10) -#range(10).slice(9, count: 3) - ---- -// Error: 2-24 array index out of bounds (index: -4, len: 3) -#(1, 2, 3).slice(0, -4) - ---- -// Test the `position` method. -#test(("Hi", "❤️", "Love").position(s => s == "❤️"), 1) -#test(("Bye", "💘", "Apart").position(s => s == "❤️"), none) -#test(("A", "B", "CDEF", "G").position(v => v.len() > 2), 2) - ---- -// Test the `filter` method. -#test(().filter(calc.even), ()) -#test((1, 2, 3, 4).filter(calc.even), (2, 4)) -#test((7, 3, 2, 5, 1).filter(x => x < 5), (3, 2, 1)) - ---- -// Test the `map` method. -#test(().map(x => x * 2), ()) -#test((2, 3).map(x => x * 2), (4, 6)) - ---- -// Test the `fold` method. -#test(().fold("hi", grid), "hi") -#test((1, 2, 3, 4).fold(0, (s, x) => s + x), 10) - ---- -// Error: 20-22 unexpected argument -#(1, 2, 3).fold(0, () => none) - ---- -// Test the `sum` method. -#test(().sum(default: 0), 0) -#test(().sum(default: []), []) -#test((1, 2, 3).sum(), 6) - ---- -// Error: 2-10 cannot calculate sum of empty array with no default -#().sum() - ---- -// Test the `product` method. -#test(().product(default: 0), 0) -#test(().product(default: []), []) -#test(([ab], 3).product(), [ab]*3) -#test((1, 2, 3).product(), 6) - ---- -// Error: 2-14 cannot calculate product of empty array with no default -#().product() - ---- -// Test the `rev` method. -#test(range(3).rev(), (2, 1, 0)) - ---- -// Test the `join` method. -#test(().join(), none) -#test((1,).join(), 1) -#test(("a", "b", "c").join(), "abc") -#test("(" + ("a", "b", "c").join(", ") + ")", "(a, b, c)") - ---- -// Error: 2-22 cannot join boolean with boolean -#(true, false).join() - ---- -// Error: 2-20 cannot join string with integer -#("a", "b").join(1) - ---- -// Test joining content. -// Ref: true -#([One], [Two], [Three]).join([, ], last: [ and ]). - ---- -// Test the `intersperse` method -#test(().intersperse("a"), ()) -#test((1,).intersperse("a"), (1,)) -#test((1, 2).intersperse("a"), (1, "a", 2)) -#test((1, 2, "b").intersperse("a"), (1, "a", 2, "a", "b")) - ---- -// Test the `chunks` method. -#test(().chunks(10), ()) -#test((1, 2, 3).chunks(10), ((1, 2, 3),)) -#test((1, 2, 3, 4, 5, 6).chunks(3), ((1, 2, 3), (4, 5, 6))) -#test((1, 2, 3, 4, 5, 6, 7, 8).chunks(3), ((1, 2, 3), (4, 5, 6), (7, 8))) - -#test(().chunks(10, exact: true), ()) -#test((1, 2, 3).chunks(10, exact: true), ()) -#test((1, 2, 3, 4, 5, 6).chunks(3, exact: true), ((1, 2, 3), (4, 5, 6))) -#test((1, 2, 3, 4, 5, 6, 7, 8).chunks(3, exact: true), ((1, 2, 3), (4, 5, 6))) - ---- -// Error: 19-20 number must be positive -#(1, 2, 3).chunks(0) - ---- -// Error: 19-21 number must be positive -#(1, 2, 3).chunks(-5) - ---- -// Test the `sorted` method. -#test(().sorted(), ()) -#test(().sorted(key: x => x), ()) -#test(((true, false) * 10).sorted(), (false,) * 10 + (true,) * 10) -#test(("it", "the", "hi", "text").sorted(), ("hi", "it", "text", "the")) -#test(("I", "the", "hi", "text").sorted(key: x => x), ("I", "hi", "text", "the")) -#test(("I", "the", "hi", "text").sorted(key: x => x.len()), ("I", "hi", "the", "text")) -#test((2, 1, 3, 10, 5, 8, 6, -7, 2).sorted(), (-7, 1, 2, 2, 3, 5, 6, 8, 10)) -#test((2, 1, 3, -10, -5, 8, 6, -7, 2).sorted(key: x => x), (-10, -7, -5, 1, 2, 2, 3, 6, 8)) -#test((2, 1, 3, -10, -5, 8, 6, -7, 2).sorted(key: x => x * x), (1, 2, 2, 3, -5, 6, -7, 8, -10)) - ---- -// Error: 12-18 unexpected argument -#().sorted(x => x) - ---- -// Test the `zip` method. -#test(().zip(()), ()) -#test((1,).zip(()), ()) -#test((1,).zip((2,)), ((1, 2),)) -#test((1, 2).zip((3, 4)), ((1, 3), (2, 4))) -#test((1, 2, 3, 4).zip((5, 6)), ((1, 5), (2, 6))) -#test(((1, 2), 3).zip((4, 5)), (((1, 2), 4), (3, 5))) -#test((1, "hi").zip((true, false)), ((1, true), ("hi", false))) -#test((1, 2, 3).zip((3, 4, 5), (6, 7, 8)), ((1, 3, 6), (2, 4, 7), (3, 5, 8))) -#test(().zip((), ()), ()) -#test((1,).zip((2,), (3,)), ((1, 2, 3),)) -#test((1, 2, 3).zip(), ((1,), (2,), (3,))) -#test(array.zip(()), ()) - - ---- -// Test the `enumerate` method. -#test(().enumerate(), ()) -#test(().enumerate(start: 5), ()) -#test(("a", "b", "c").enumerate(), ((0, "a"), (1, "b"), (2, "c"))) -#test(("a", "b", "c").enumerate(start: 1), ((1, "a"), (2, "b"), (3, "c"))) -#test(("a", "b", "c").enumerate(start: 42), ((42, "a"), (43, "b"), (44, "c"))) -#test(("a", "b", "c").enumerate(start: -7), ((-7, "a"), (-6, "b"), (-5, "c"))) - ---- -// Test the `dedup` method. -#test(().dedup(), ()) -#test((1,).dedup(), (1,)) -#test((1, 1).dedup(), (1,)) -#test((1, 2, 1).dedup(), (1, 2)) -#test(("Jane", "John", "Eric").dedup(), ("Jane", "John", "Eric")) -#test(("Jane", "John", "Eric", "John").dedup(), ("Jane", "John", "Eric")) - ---- -// Test the `dedup` with the `key` argument. -#test((1, 2, 3, 4, 5, 6).dedup(key: x => calc.rem(x, 2)), (1, 2)) -#test((1, 2, 3, 4, 5, 6).dedup(key: x => calc.rem(x, 3)), (1, 2, 3)) -#test(("Hello", "World", "Hi", "There").dedup(key: x => x.len()), ("Hello", "Hi")) -#test(("Hello", "World", "Hi", "There").dedup(key: x => x.at(0)), ("Hello", "World", "There")) - ---- -// Error: 9-26 unexpected argument: val -#().zip(val: "applicable") - ---- -// Error: 13-30 unexpected argument: val -#().zip((), val: "applicable") - ---- -// Error: 32-37 cannot divide by zero -#(1, 2, 0, 3).sorted(key: x => 5 / x) - ---- -// Error: 2-26 cannot compare content and content -#([Hi], [There]).sorted() - ---- -// Error: 2-26 cannot compare 3em with 2pt -#(1pt, 2pt, 3em).sorted() - ---- -// Error: 42-52 unexpected argument -#((k: "a", v: 2), (k: "b", v: 1)).sorted(it => it.v) - ---- -// Error: 2-18 array index out of bounds (index: -4, len: 3) and no default value was specified -#(1, 2, 3).at(-4) - ---- -// Error: 3-4 unclosed delimiter -#{(} - -// Error: 2-3 unclosed delimiter -#{)} - -// Error: 4-6 unexpected end of block comment -#(1*/2) - -// Error: 6-8 invalid number suffix: u -#(1, 1u 2) - -// Error: 3-4 unexpected comma -#(,1) - -// Missing expression makes named pair incomplete, making this an empty array. -// Error: 5 expected expression -#(a:) - -// Named pair after this is already identified as an array. -// Error: 6-10 expected expression, found named pair -#(1, b: 2) - -// Keyed pair after this is already identified as an array. -// Error: 6-14 expected expression, found keyed pair -#(1, "key": 2) diff --git a/tests/typ/compiler/backtracking.typ b/tests/typ/compiler/backtracking.typ deleted file mode 100644 index 9c3ab8ec..00000000 --- a/tests/typ/compiler/backtracking.typ +++ /dev/null @@ -1,33 +0,0 @@ -// Ensure that parser backtracking doesn't lead to exponential time consumption. -// If this regresses, the test suite will not terminate, which is a bit -// unfortunate compared to a good error, but at least we know something is up. -// -// Ref: false - ---- -#{ - let s = "(x: 1) => x" - let pat = "(x: {}) => 1 + x()" - for _ in range(50) { - s = pat.replace("{}", s) - } - test(eval(s)(), 51) -} - ---- -#{ - let s = "(x) = 1" - let pat = "(x: {_}) = 1" - for _ in range(100) { - s = pat.replace("_", s) - } - // Error: 8-9 cannot destructure integer - eval(s) -} - ---- -// Test whitespace after memoized part. -#( (x: () => 1 ) => 1 ) -// ------- -// This is memoized and we want to ensure that whitespace after this -// is handled correctly. diff --git a/tests/typ/compiler/block.typ b/tests/typ/compiler/block.typ deleted file mode 100644 index 48c9fefc..00000000 --- a/tests/typ/compiler/block.typ +++ /dev/null @@ -1,145 +0,0 @@ -// Test code blocks. -// Ref: false - ---- -// Ref: true - -// Evaluates to join of none, [My ] and the two loop bodies. -#{ - let parts = ("my fri", "end.") - [Hello, ] - for s in parts [#s] -} - -// Evaluates to join of the content and strings. -#{ - [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. -#test({ "hello" }, "hello") - -// Evaluates to string. -#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 -}, str) - ---- -// Some things can't be joined. -#{ - [A] - // Error: 3-4 cannot join content with integer - 1 - [B] -} - ---- -// Block directly in markup also creates a scope. -#{ let x = 1 } - -// Error: 7-8 unknown variable: x -#test(x, 1) - ---- -// Block in expression does create a scope. -#let a = { - let b = 1 - b -} - -#test(a, 1) - -// Error: 3-4 unknown variable: b -#{b} - ---- -// Double block creates a scope. -#{{ - import "module.typ": b - test(b, 1) -}} - -// Error: 2-3 unknown variable: b -#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") -} - ---- -// Content blocks also create a scope. -#[#let x = 1] - -// Error: 2-3 unknown variable: x -#x - ---- -// Multiple unseparated expressions in one line. - -// Error: 2-4 invalid number suffix: u -#1u - -// Should output `1`. -// Error: 4 expected semicolon or line break -#{1 2} - -// Should output `2`. -// Error: 13 expected semicolon or line break -// Error: 23 expected semicolon or line break -#{let x = -1 let y = 3 x + y} - -// Should output `3`. -#{ - // Error: 7-10 expected pattern, found string - for "v" - - // Error: 8 expected keyword `in` - // Error: 22 expected block - for v let z = 1 + 2 - - z -} - ---- -// Error: 2-3 unclosed delimiter -#{ - ---- -// Error: 2-3 unexpected closing brace -#} diff --git a/tests/typ/compiler/break-continue.typ b/tests/typ/compiler/break-continue.typ deleted file mode 100644 index 4c4738bb..00000000 --- a/tests/typ/compiler/break-continue.typ +++ /dev/null @@ -1,162 +0,0 @@ -// Test break and continue in loops. -// Ref: false - ---- -// Test break. - -#let var = 0 -#let error = false - -#for i in range(10) { - var += i - if i > 5 { - break - error = true - } -} - -#test(var, 21) -#test(error, false) - ---- -// Test joining with break. - -#let i = 0 -#let x = while true { - i += 1 - str(i) - if i >= 5 { - "." - break - } -} - -#test(x, "12345.") - ---- -// Test continue. - -#let i = 0 -#let x = 0 - -#while x < 8 { - i += 1 - if calc.rem(i, 3) == 0 { - continue - } - x += i -} - -// If continue did not work, this would equal 10. -#test(x, 12) - ---- -// Test joining with continue. - -#let x = for i in range(5) { - "a" - if calc.rem(i, 3) == 0 { - "_" - continue - } - str(i) -} - -#test(x, "a_a1a2a_a4") - ---- -// Test break outside of loop. -#let f() = { - // Error: 3-8 cannot break outside of loop - break -} - -#for i in range(1) { - f() -} - ---- -// Test break in function call. -#let identity(x) = x -#let out = for i in range(5) { - "A" - identity({ - "B" - break - }) - "C" -} - -#test(out, "AB") - ---- -// Test continue outside of loop. - -// Error: 12-20 cannot continue outside of loop -#let x = { continue } - ---- -// Error: 2-10 cannot continue outside of loop -#continue - ---- -// Ref: true -// Should output `Hello World 🌎`. -#for _ in range(10) { - [Hello ] - [World #{ - [🌎] - break - }] -} - ---- -// Ref: true -// Should output `Some` in red, `Some` in blue and `Last` in green. -// Everything should be in smallcaps. -#for color in (red, blue, green, yellow) [ - #set text(font: "Roboto") - #show: it => text(fill: color, it) - #smallcaps(if color != green [ - Some - ] else [ - Last - #break - ]) -] - ---- -// Ref: true -// Test break in set rule. -// Should output `Hi` in blue. -#for i in range(10) { - [Hello] - set text(blue, ..break) - [Not happening] -} - ---- -// Test second block during break flow. -// Ref: true - -#for i in range(10) { - table( - { [A]; break }, - for _ in range(3) [B] - ) -} - ---- -// Ref: true -// Test continue while destructuring. -// Should output "one = I \ two = II \ one = I". -#for num in (1, 2, 3, 1) { - let (word, roman) = if num == 1 { - ("one", "I") - } else if num == 2 { - ("two", "II") - } else { - continue - } - [#word = #roman \ ] -} diff --git a/tests/typ/compiler/bytes.typ b/tests/typ/compiler/bytes.typ deleted file mode 100644 index a9249bdd..00000000 --- a/tests/typ/compiler/bytes.typ +++ /dev/null @@ -1,32 +0,0 @@ -// Test the bytes type. -// Ref: false - ---- -#let data = read("/assets/images/rhino.png", encoding: none) -#test(data.len(), 232243) -#test(data.slice(0, count: 5), bytes((137, 80, 78, 71, 13))) -#test(str(data.slice(1, 4)), "PNG") -#test(repr(data), "bytes(232243)") - ---- -#test(str(bytes(range(0x41, 0x50))), "ABCDEFGHIJKLMNO") -#test(array(bytes("Hello")), (0x48, 0x65, 0x6C, 0x6C, 0x6F)) - ---- -// Test addition and joining. -#test(bytes((1, 2)) + bytes(()), bytes((1, 2))) -#test(bytes((1, 2)) + bytes((3, 4)), bytes((1, 2, 3, 4))) -#test(bytes(()) + bytes((3, 4)), bytes((3, 4))) -#test(str({ - bytes("Hello") - bytes((0x20,)) - bytes("World") -}), "Hello World") - ---- -// Error: 8-14 expected string, array, or bytes, found dictionary -#bytes((a: 1)) - ---- -// Error: 8-15 expected array, bytes, or version, found string -#array("hello") diff --git a/tests/typ/compiler/call.typ b/tests/typ/compiler/call.typ deleted file mode 100644 index 0c225a1c..00000000 --- a/tests/typ/compiler/call.typ +++ /dev/null @@ -1,111 +0,0 @@ -// Test function calls. -// Ref: false - ---- -// Ref: true - -// Omitted space. -#let f() = {} -#[#f()*Bold*] - -// Call return value of function with body. -#let f(x, body) = (y) => [#x] + body + [#y] -#f(1)[2](3) - -// Don't parse this as a function. -#test (it) - -#let f(body) = body -#f[A] -#f()[A] -#f([A]) - -#let g(a, b) = a + b -#g[A][B] -#g([A], [B]) -#g()[A][B] - ---- -// Trailing comma. -#test(1 + 1, 2,) - -// Call function assigned to variable. -#let alias = type -#test(alias(alias), type) - -// Callee expressions. -#{ - // Wrapped in parens. - test((type)("hi"), str) - - // Call the return value of a function. - let adder(dx) = x => x + dx - test(adder(2)(5), 7) -} - ---- -// Error: 26-30 duplicate argument: font -#set text(font: "Arial", font: "Helvetica") - ---- -// Error: 4-15 the argument `amount` is positional -// Hint: 4-15 try removing `amount:` -#h(amount: 0.5) - ---- -// Error: 2-6 expected function, found boolean -#true() - ---- -#let x = "x" - -// Error: 2-3 expected function, found string -#x() - ---- -#let f(x) = x - -// Error: 2-6 expected function, found integer -#f(1)(2) - ---- -#let f(x) = x - -// Error: 2-6 expected function, found content -#f[1](2) - ---- -// Error: 7-8 unexpected colon -#func(:) - -// Error: 10-12 unexpected end of block comment -#func(a:1*/) - -// Error: 8 expected comma -#func(1 2) - -// Error: 7-8 expected identifier, found integer -// Error: 9 expected expression -#func(1:) - -// Error: 7-8 expected identifier, found integer -#func(1:2) - -// Error: 7-12 expected identifier, found string -#func("abc": 2) - -// Error: 7-10 expected identifier, found group -#func((x):1) - ---- -// Error: 6-7 unclosed delimiter -#func[`a]` - ---- -// Error: 7-8 unclosed delimiter -#{func(} - ---- -// Error: 6-7 unclosed delimiter -// Error: 1:7-2:1 unclosed string -#func("] diff --git a/tests/typ/compiler/closure.typ b/tests/typ/compiler/closure.typ deleted file mode 100644 index 29c092b7..00000000 --- a/tests/typ/compiler/closure.typ +++ /dev/null @@ -1,219 +0,0 @@ -// Test closures. -// Ref: false - ---- -// Don't parse closure directly in content. -// Ref: true - -#let x = "x" - -// Should output `x => y`. -#x => y - ---- -// 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. -#{ - let chain = (f, g) => (x) => f(g(x)) - let f = x => x + 1 - let g = x => 2 * x - let h = chain(f, g) - test(h(2), 5) -} - ---- -// Capture environment. -#{ - let mark = "!" - let greet = { - let hi = "Hi" - name => { - hi + ", " + name + mark - } - } - - test(greet("Typst"), "Hi, Typst!") - - // Changing the captured variable after the closure definition has no effect. - mark = "?" - test(greet("Typst"), "Hi, Typst!") -} - ---- -// Redefined variable. -#{ - let x = 1 - let f() = { - let x = x + 2 - x - } - test(f(), 3) -} - ---- -// Import bindings. -#{ - let b = "module.typ" - let f() = { - import b: b - b - } - test(f(), 1) -} - ---- -// For loop bindings. -#{ - let v = (1, 2, 3) - let f() = { - let s = 0 - for v in v { s += v } - s - } - test(f(), 6) -} - ---- -// Let + closure bindings. -#{ - let g = "hi" - let f() = { - let g() = "bye" - g() - } - test(f(), "bye") -} - ---- -// Parameter bindings. -#{ - let x = 5 - let g() = { - let f(x, y: x) = x + y - f - } - - test(g()(8), 13) -} - ---- -// Don't leak environment. -#{ - // Error: 16-17 unknown variable: x - let func() = x - let x = "hi" - func() -} - ---- -// Too few arguments. -#{ - let types(x, y) = "[" + str(type(x)) + ", " + str(type(y)) + "]" - test(types(14%, 12pt), "[ratio, length]") - - // Error: 8-21 missing argument: y - test(types("nope"), "[string, none]") -} - ---- -// Too many arguments. -#{ - let f(x) = x + 1 - - // Error: 8-13 unexpected argument - f(1, "two", () => x) -} - ---- -// Mutable method with capture in argument. -#let x = "b" -#let f() = { - let a = (b: 5) - a.at(x) = 10 - a -} -#f() - ---- -#let x = () -#let f() = { - // Error: 3-4 variables from outside the function are read-only and cannot be modified - x.at(1) = 2 -} -#f() - ---- -// Named arguments. -#{ - let greet(name, birthday: false) = { - if birthday { "Happy Birthday, " } else { "Hey, " } + name + "!" - } - - test(greet("Typst"), "Hey, Typst!") - test(greet("Typst", birthday: true), "Happy Birthday, Typst!") - - // Error: 23-35 unexpected argument: whatever - test(greet("Typst", whatever: 10)) -} - ---- -// Parameter unpacking. -#let f((a, b), ..c) = (a, b, c) -#test(f((1, 2), 3, 4), (1, 2, (3, 4))) - -#let f((k: a, b), c: 3, (d,)) = (a, b, c, d) -#test(f((k: 1, b: 2), (4,)), (1, 2, 3, 4)) - -// Error: 8-14 expected identifier, found destructuring pattern -#let f((a, b): 0) = none - -// Error: 10-19 expected pattern, found array -#let f(..(a, b: c)) = none - -// Error: 10-16 expected pattern, found array -#let f(..(a, b)) = none - ---- -// Error: 11-12 duplicate parameter: x -#let f(x, x) = none - ---- -// Error: 21 expected comma -// Error: 22-23 expected pattern, found integer -// Error: 24-25 unexpected plus -// Error: 26-27 expected pattern, found integer -#let f = (x: () => 1 2 + 3) => 4 - ---- -// Error: 14-15 duplicate parameter: a -// Error: 23-24 duplicate parameter: b -// Error: 35-36 duplicate parameter: b -#let f(a, b, a: none, b: none, c, b) = none - ---- -// Error: 13-14 duplicate parameter: a -#let f(a, ..a) = none - ---- -// Error: 7-14 expected pattern, found string -#((a, "named": b) => none) - ---- -// Error: 10-15 expected pattern, found string -#let foo("key": b) = key - ---- -// Error: 10-14 expected pattern, found `none` -// Hint: 10-14 keyword `none` is not allowed as an identifier; try `none_` instead -#let foo(none: b) = key - ---- -// Error: 10-11 expected identifier, found underscore -#let foo(_: 3) = none diff --git a/tests/typ/compiler/color.typ b/tests/typ/compiler/color.typ deleted file mode 100644 index ac83355d..00000000 --- a/tests/typ/compiler/color.typ +++ /dev/null @@ -1,101 +0,0 @@ -// Test color modification methods. - ---- -// Test CMYK color conversion. -#let c = cmyk(50%, 64%, 16%, 17%) -#stack( - dir: ltr, - spacing: 1fr, - rect(width: 1cm, fill: cmyk(69%, 11%, 69%, 41%)), - rect(width: 1cm, fill: c), - rect(width: 1cm, fill: c.negate(space: cmyk)), -) - -#for x in range(0, 11) { - box(square(size: 9pt, fill: c.lighten(x * 10%))) -} -#for x in range(0, 11) { - box(square(size: 9pt, fill: c.darken(x * 10%))) -} - ---- -// The the different color spaces -#let col = rgb(50%, 64%, 16%) -#box(square(size: 9pt, fill: col)) -#box(square(size: 9pt, fill: rgb(col))) -#box(square(size: 9pt, fill: oklab(col))) -#box(square(size: 9pt, fill: oklch(col))) -#box(square(size: 9pt, fill: luma(col))) -#box(square(size: 9pt, fill: cmyk(col))) -#box(square(size: 9pt, fill: color.linear-rgb(col))) -#box(square(size: 9pt, fill: color.hsl(col))) -#box(square(size: 9pt, fill: color.hsv(col))) - ---- -// Colors outside the sRGB gamut. -#box(square(size: 9pt, fill: oklab(90%, -0.2, -0.1))) -#box(square(size: 9pt, fill: oklch(50%, 0.5, 0deg))) - ---- -// Test hue rotation -#let col = rgb(50%, 64%, 16%) - -// Oklch -#for x in range(0, 11) { - box(square(size: 9pt, fill: rgb(col).rotate(x * 36deg))) -} - -// HSL -#for x in range(0, 11) { - box(square(size: 9pt, fill: rgb(col).rotate(x * 36deg, space: color.hsl))) -} - -// HSV -#for x in range(0, 11) { - box(square(size: 9pt, fill: rgb(col).rotate(x * 36deg, space: color.hsv))) -} - ---- -// Test saturation -#let col = color.hsl(180deg, 0%, 50%) -#for x in range(0, 11) { - box(square(size: 9pt, fill: col.saturate(x * 10%))) -} - -#let col = color.hsl(180deg, 100%, 50%) -#for x in range(0, 11) { - box(square(size: 9pt, fill: col.desaturate(x * 10%))) -} - -#let col = color.hsv(180deg, 0%, 50%) -#for x in range(0, 11) { - box(square(size: 9pt, fill: col.saturate(x * 10%))) -} - -#let col = color.hsv(180deg, 100%, 50%) -#for x in range(0, 11) { - box(square(size: 9pt, fill: col.desaturate(x * 10%))) -} - ---- -// Test gray color modification. -// Ref: false -#test-repr(luma(20%).lighten(50%), luma(60%)) -#test-repr(luma(80%).darken(20%), luma(64%)) -#test-repr(luma(80%).negate(space: luma), luma(20%)) - ---- -// Test alpha modification. -// Ref: false -#test-repr(luma(100%, 100%).transparentize(50%), luma(100%, 50%)) -#test-repr(luma(100%, 100%).transparentize(75%), luma(100%, 25%)) -#test-repr(luma(100%, 50%).transparentize(50%), luma(100%, 25%)) -#test-repr(luma(100%, 10%).transparentize(250%), luma(100%, 0%)) -#test-repr(luma(100%, 40%).transparentize(-50%), luma(100%, 70%)) -#test-repr(luma(100%, 0%).transparentize(-100%), luma(100%, 100%)) - -#test-repr(luma(100%, 50%).opacify(50%), luma(100%, 75%)) -#test-repr(luma(100%, 20%).opacify(100%), luma(100%, 100%)) -#test-repr(luma(100%, 100%).opacify(250%), luma(100%, 100%)) -#test-repr(luma(100%, 50%).opacify(-50%), luma(100%, 25%)) -#test-repr(luma(100%, 0%).opacify(0%), luma(100%, 0%)) diff --git a/tests/typ/compiler/comment.typ b/tests/typ/compiler/comment.typ deleted file mode 100644 index 31025de6..00000000 --- a/tests/typ/compiler/comment.typ +++ /dev/null @@ -1,34 +0,0 @@ -// Test line and block comments. - ---- -// Line comment acts as spacing. -A// you -B - -// Block comment does not act as spacing, nested block comments. -C/* - /* */ -*/D - -// Works in code. -#test(type(/*1*/ 1) // -, int) - -// End of block comment in line comment. -// Hello */ - -// Nested "//" doesn't count as line comment. -/* // */ -E - -/*//*/ -This is a comment. -*/*/ - ---- -// End should not appear without start. -// Error: 7-9 unexpected end of block comment -/* */ */ - -// Unterminated is okay. -/* diff --git a/tests/typ/compiler/construct.typ b/tests/typ/compiler/construct.typ deleted file mode 100644 index da077e7e..00000000 --- a/tests/typ/compiler/construct.typ +++ /dev/null @@ -1,31 +0,0 @@ -// Test constructors. - ---- -// Ensure that constructor styles aren't passed down the tree. -// The inner list should have no extra indent. -#set par(leading: 2pt) -#list(body-indent: 20pt, [First], list[A][B]) - ---- -// Ensure that constructor styles win, but not over outer styles. -// The outer paragraph should be right-aligned, -// but the B should be center-aligned. -#set list(marker: [>]) -#list(marker: [--])[ - #rect(width: 2cm, fill: conifer, inset: 4pt, list[A]) -] - ---- -// The inner rectangle should also be yellow here. -// (and therefore invisible) -#[#set rect(fill: yellow);#text(1em, rect(inset: 5pt, rect()))] - ---- -// The inner rectangle should not be yellow here. -A #box(rect(fill: yellow, inset: 5pt, rect())) B - ---- -// The constructor property should still work -// when there are recursive show rules. -#show enum: set text(blue) -#enum(numbering: "(a)", [A], enum[B]) diff --git a/tests/typ/compiler/content-field.typ b/tests/typ/compiler/content-field.typ deleted file mode 100644 index 96ce1dca..00000000 --- a/tests/typ/compiler/content-field.typ +++ /dev/null @@ -1,63 +0,0 @@ -// Tests content field access. - ---- -// Ensure that fields from set rules are materialized into the element before -// a show rule runs. -#set table(columns: (10pt, auto)) -#show table: it => it.columns -#table[A][B][C][D] - ---- -// Test it again with a different element. -#set heading(numbering: "(I)") -#show heading: set text(size: 11pt, weight: "regular") -#show heading: it => it.numbering -= Heading - ---- -// Test it with query. -#set raw(lang: "rust") -#context query(<myraw>).first().lang -`raw` <myraw> - ---- -// Integrated test for content fields. -#let compute(equation, ..vars) = { - let vars = vars.named() - let f(elem) = { - let func = elem.func() - if func == text { - let text = elem.text - if regex("^\d+$") in text { - int(text) - } else if text in vars { - int(vars.at(text)) - } else { - panic("unknown math variable: " + text) - } - } else if func == math.attach { - let value = f(elem.base) - if elem.has("t") { - value = calc.pow(value, f(elem.t)) - } - value - } else if elem.has("children") { - elem - .children - .filter(v => v != [ ]) - .split[+] - .map(xs => xs.fold(1, (prod, v) => prod * f(v))) - .fold(0, (sum, v) => sum + v) - } - } - let result = f(equation.body) - [With ] - vars - .pairs() - .map(p => $#p.first() = #p.last()$) - .join(", ", last: " and ") - [ we have:] - $ equation = result $ -} - -#compute($x y + y^2$, x: 2, y: 3) diff --git a/tests/typ/compiler/delayed-error.typ b/tests/typ/compiler/delayed-error.typ deleted file mode 100644 index eff6b85b..00000000 --- a/tests/typ/compiler/delayed-error.typ +++ /dev/null @@ -1,11 +0,0 @@ -// Test that errors in show rules are delayed: There can be multiple at once. - ---- -// Error: 21-34 panicked with: "hey1" -#show heading: _ => panic("hey1") - -// Error: 20-33 panicked with: "hey2" -#show strong: _ => panic("hey2") - -= Hello -*strong* diff --git a/tests/typ/compiler/dict.typ b/tests/typ/compiler/dict.typ deleted file mode 100644 index 552b243c..00000000 --- a/tests/typ/compiler/dict.typ +++ /dev/null @@ -1,160 +0,0 @@ -// Test dictionaries. -// Ref: false - ---- -// Ref: true - -// Empty -#(:) - -// Two pairs and string key. -#let dict = (normal: 1, "spacy key": 2) -#dict - -#test(dict.normal, 1) -#test(dict.at("spacy key"), 2) - ---- -// Test lvalue and rvalue access. -#{ - let dict = (a: 1, "b b": 1) - dict.at("b b") += 1 - dict.state = (ok: true, err: false) - test(dict, (a: 1, "b b": 2, state: (ok: true, err: false))) - test(dict.state.ok, true) - dict.at("state").ok = false - test(dict.state.ok, false) - test(dict.state.err, false) -} - ---- -// Test rvalue missing key. -#{ - let dict = (a: 1, b: 2) - // Error: 11-23 dictionary does not contain key "c" and no default value was specified - let x = dict.at("c") -} - ---- -// Test default value. -#test((a: 1, b: 2).at("b", default: 3), 2) -#test((a: 1, b: 2).at("c", default: 3), 3) - ---- -// Test insert. -#{ - let dict = (a: 1, b: 2) - dict.insert("b", 3) - test(dict, (a: 1, b: 3)) - dict.insert("c", 5) - test(dict, (a: 1, b: 3, c: 5)) -} - ---- -// Test remove with default value. -#{ - let dict = (a: 1, b: 2) - test(dict.remove("b", default: 3), 2) -} - -#{ - let dict = (a: 1, b: 2) - test(dict.remove("c", default: 3), 3) -} - ---- -// Missing lvalue is not automatically none-initialized. -#{ - let dict = (:) - // Error: 3-9 dictionary does not contain key "b" - // Hint: 3-9 use `insert` to add or update values - dict.b += 1 -} - ---- -// Test dictionary methods. -#let dict = (a: 3, c: 2, b: 1) -#test("c" in dict, true) -#test(dict.len(), 3) -#test(dict.values(), (3, 2, 1)) -#test(dict.pairs().map(p => p.first() + str(p.last())).join(), "a3c2b1") - -#dict.remove("c") -#test("c" in dict, false) -#test(dict, (a: 3, b: 1)) - ---- -// Test dictionary constructor -#dictionary(sys).at("version") -#dictionary(sys).at("no_crash", default: none) - ---- -// Test that removal keeps order. -#let dict = (a: 1, b: 2, c: 3, d: 4) -#dict.remove("b") -#test(dict.keys(), ("a", "c", "d")) - ---- -// Error: 24-29 duplicate key: first -#(first: 1, second: 2, first: 3) - ---- -// Error: 17-20 duplicate key: a -#(a: 1, "b": 2, "a": 3) - ---- -// Simple expression after already being identified as a dictionary. -// Error: 9-10 expected named or keyed pair, found identifier -#(a: 1, b) - -// Identified as dictionary due to initial colon. -// The boolean key is allowed for now since it will only cause an error at the evaluation stage. -// Error: 4-5 expected named or keyed pair, found integer -// Error: 17 expected expression -#(:1 b:"", true:) - ---- -// Error: 3-15 cannot mutate a temporary value -#((key: "val").other = "some") - ---- -#{ - let dict = ( - call-me: () => 1, - ) - // Error: 8-15 type dictionary has no method `call-me` - // Hint: 8-15 to call the function stored in the dictionary, surround the field access with parentheses, e.g. `(dict.call-me)(..)` - dict.call-me() -} - ---- -#{ - let dict = ( - nonfunc: 1 - ) - - // Error: 8-15 type dictionary has no method `nonfunc` - // Hint: 8-15 did you mean to access the field `nonfunc`? - dict.nonfunc() -} - ---- -#let a = "hello" -#let b = "world" -#let c = "value" -#let d = "conflict" - -#assert.eq(((a): b), ("hello": "world")) -#assert.eq(((a): 1, (a): 2), ("hello": 2)) -#assert.eq((hello: 1, (a): 2), ("hello": 2)) -#assert.eq((a + b: c, (a + b): d, (a): "value2", a: "value3"), ("helloworld": "conflict", "hello": "value2", "a": "value3")) - ---- -// Error: 7-10 expected identifier, found group -// Error: 12-14 expected pattern, found integer -#let ((a): 10) = "world" - ---- -// Error: 3-7 expected string, found boolean -// Error: 16-18 expected string, found integer -#(true: false, 42: 3) diff --git a/tests/typ/compiler/duration.typ b/tests/typ/compiler/duration.typ deleted file mode 100644 index 1d831a6f..00000000 --- a/tests/typ/compiler/duration.typ +++ /dev/null @@ -1,104 +0,0 @@ -// Test durations. -// Ref: false - ---- -// Test negating durations. -#test(-duration(hours: 2), duration(hours: -2)) - ---- -// Test adding and subtracting durations. -#test(duration(weeks: 1, hours: 1), duration(weeks: 1) + duration(hours: 1)) -#test(duration(weeks: 1, hours: -1), duration(weeks: 1) - duration(hours: 1)) -#test(duration(days: 6, hours: 23), duration(weeks: 1) - duration(hours: 1)) - ---- -// Test adding and subtracting durations and dates. -#let d = datetime(day: 1, month: 1, year: 2000) -#let d2 = datetime(day: 1, month: 2, year: 2000) -#test(d + duration(weeks: 2), datetime(day: 15, month: 1, year: 2000)) -#test(d + duration(days: 3), datetime(day: 4, month: 1, year: 2000)) -#test(d + duration(weeks: 1, days: 3), datetime(day: 11, month: 1, year: 2000)) -#test(d2 + duration(days: -1), datetime(day: 31, month: 1, year: 2000)) -#test(d2 + duration(days: -3), datetime(day: 29, month: 1, year: 2000)) -#test(d2 + duration(weeks: -1), datetime(day: 25, month: 1, year: 2000)) -#test(d + duration(days: -1), datetime(day: 31, month: 12, year: 1999)) -#test(d + duration(weeks: 1, days: -7), datetime(day: 1, month: 1, year: 2000)) -#test(d2 - duration(days: 1), datetime(day: 31, month: 1, year: 2000)) -#test(d2 - duration(days: 3), datetime(day: 29, month: 1, year: 2000)) -#test(d2 - duration(weeks: 1), datetime(day: 25, month: 1, year: 2000)) -#test(d - duration(days: 1), datetime(day: 31, month: 12, year: 1999)) -#test(datetime(day: 31, month: 1, year: 2000) + duration(days: 1), d2) -#test( - datetime(day: 31, month: 12, year: 2000) + duration(days: 1), - datetime(day: 1, month: 1, year: 2001), -) - ---- -// Test adding and subtracting durations and times. -#let a = datetime(hour: 12, minute: 0, second: 0) -#test(a + duration(hours: 1, minutes: -60), datetime(hour: 12, minute: 0, second: 0)) -#test(a + duration(hours: 2), datetime(hour: 14, minute: 0, second: 0)) -#test(a + duration(minutes: 10), datetime(hour: 12, minute: 10, second: 0)) -#test(a + duration(seconds: 30), datetime(hour: 12, minute: 0, second: 30)) -#test(a + duration(hours: -2), datetime(hour: 10, minute: 0, second: 0)) -#test(a - duration(hours: 2), datetime(hour: 10, minute: 0, second: 0)) -#test(a + duration(minutes: -10), datetime(hour: 11, minute: 50, second: 0)) -#test(a - duration(minutes: 10), datetime(hour: 11, minute: 50, second: 0)) -#test(a + duration(seconds: -30), datetime(hour: 11, minute: 59, second: 30)) -#test(a - duration(seconds: 30), datetime(hour: 11, minute: 59, second: 30)) -#test( - a + duration(hours: 1, minutes: 13, seconds: 13), - datetime(hour: 13, minute: 13, second: 13), -) - ---- -// Test adding and subtracting durations and datetimes. -#test( - datetime(day: 1, month: 1, year: 2000, hour: 12, minute: 0, second: 0) - + duration(weeks: 1, days: 3, hours: -13, minutes: 10, seconds: -10 ), - datetime(day: 10, month: 1, year: 2000, hour: 23, minute: 9, second: 50), -) -#test( - datetime(day: 1, month: 1, year: 2000, hour: 12, minute: 0, second: 0) - + duration(weeks: 1, days: 3, minutes: 10) - - duration(hours: 13, seconds: 10), - datetime(day: 10, month: 1, year: 2000, hour: 23, minute: 9, second: 50), -) - ---- -// Test subtracting dates. -#let a = datetime(hour: 12, minute: 0, second: 0) -#let b = datetime(day: 1, month: 1, year: 2000) -#test(datetime(hour: 14, minute: 0, second: 0) - a, duration(hours: 2)) -#test(datetime(hour: 14, minute: 0, second: 0) - a, duration(minutes: 120)) -#test(datetime(hour: 13, minute: 0, second: 0) - a, duration(seconds: 3600)) -#test(datetime(day: 1, month: 2, year: 2000) - b, duration(days: 31)) -#test(datetime(day: 15, month: 1, year: 2000) - b, duration(weeks: 2)) - ---- -// Test multiplying and dividing durations with numbers. -#test(duration(minutes: 10) * 6, duration(hours: 1)) -#test(duration(minutes: 10) * 2, duration(minutes: 20)) -#test(duration(minutes: 10) * 2.5, duration(minutes: 25)) -#test(duration(minutes: 10) / 2, duration(minutes: 5)) -#test(duration(minutes: 10) / 2.5, duration(minutes: 4)) - ---- -// Test dividing durations with durations -#test(duration(minutes: 20) / duration(hours: 1), 1 / 3) -#test(duration(minutes: 20) / duration(minutes: 10), 2) -#test(duration(minutes: 20) / duration(minutes: 8), 2.5) - ---- -// Test comparing durations -#test(duration(minutes: 20) > duration(minutes: 10), true) -#test(duration(minutes: 20) >= duration(minutes: 10), true) -#test(duration(minutes: 10) < duration(minutes: 20), true) -#test(duration(minutes: 10) <= duration(minutes: 20), true) -#test(duration(minutes: 10) == duration(minutes: 10), true) -#test(duration(minutes: 10) != duration(minutes: 20), true) -#test(duration(minutes: 10) <= duration(minutes: 10), true) -#test(duration(minutes: 10) >= duration(minutes: 10), true) -#test(duration(minutes: 20) < duration(minutes: 10), false) -#test(duration(minutes: 20) <= duration(minutes: 10), false) -#test(duration(minutes: 20) == duration(minutes: 10), false) diff --git a/tests/typ/compiler/embedded-expr.typ b/tests/typ/compiler/embedded-expr.typ deleted file mode 100644 index ee6e07f9..00000000 --- a/tests/typ/compiler/embedded-expr.typ +++ /dev/null @@ -1,22 +0,0 @@ -// Test embedded expressions. -// Ref: false - ---- -// Error: 6-8 expected pattern, found keyword `as` -// Hint: 6-8 keyword `as` is not allowed as an identifier; try `as_` instead -#let as = 1 + 2 - ---- -#{ - // Error: 7-9 expected pattern, found keyword `as` - // Hint: 7-9 keyword `as` is not allowed as an identifier; try `as_` instead - let as = 10 -} - ---- -// Error: 2-2 expected expression -# - ---- -// Error: 2-2 expected expression -# hello diff --git a/tests/typ/compiler/field.typ b/tests/typ/compiler/field.typ deleted file mode 100644 index 35768ec5..00000000 --- a/tests/typ/compiler/field.typ +++ /dev/null @@ -1,200 +0,0 @@ -// Test field access. -// Ref: false - ---- -// Test field on dictionary. -#let dict = (nothing: "ness", hello: "world") -#test(dict.nothing, "ness") -#{ - let world = dict - .hello - - test(world, "world") -} - ---- -// Test fields on elements. -#show list: it => { - test(it.children.len(), 3) -} - -- A -- B -- C - ---- -// Test fields on function scopes. -#enum.item -#assert.eq -#assert.ne - ---- -// Error: 9-16 function `assert` does not contain field `invalid` -#assert.invalid - ---- -// Error: 7-14 function `enum` does not contain field `invalid` -#enum.invalid - ---- -// Error: 7-14 function `enum` does not contain field `invalid` -#enum.invalid() - ---- -// Closures cannot have fields. -#let f(x) = x -// Error: 4-11 cannot access fields on user-defined functions -#f.invalid - ---- -// Error: 6-13 dictionary does not contain key "invalid" -#(:).invalid - ---- -// Error: 8-10 cannot access fields on type boolean -#false.ok - ---- -// Error: 25-28 content does not contain field "fun" -#show heading: it => it.fun -= A - ---- -// Error: 9-13 cannot access fields on type boolean -#{false.true} - ---- -// Test relative length fields. -#test((100% + 2em + 2pt).ratio, 100%) -#test((100% + 2em + 2pt).length, 2em + 2pt) -#test((100% + 2pt).length, 2pt) -#test((100% + 2pt - 2pt).length, 0pt) -#test((56% + 2pt - 56%).ratio, 0%) - ---- -// Test length fields. -#test((1pt).em, 0.0) -#test((1pt).abs, 1pt) -#test((3em).em, 3.0) -#test((3em).abs, 0pt) -#test((2em + 2pt).em, 2.0) -#test((2em + 2pt).abs, 2pt) - ---- -// Test stroke fields for simple strokes. -#test((1em + blue).paint, blue) -#test((1em + blue).thickness, 1em) -#test((1em + blue).cap, auto) -#test((1em + blue).join, auto) -#test((1em + blue).dash, auto) -#test((1em + blue).miter-limit, auto) - ---- -// Test complex stroke fields. -#let r1 = rect(stroke: (paint: cmyk(1%, 2%, 3%, 4%), thickness: 4em + 2pt, cap: "round", join: "bevel", miter-limit: 5.0, dash: none)) -#let r2 = rect(stroke: (paint: cmyk(1%, 2%, 3%, 4%), thickness: 4em + 2pt, cap: "round", join: "bevel", miter-limit: 5.0, dash: (3pt, "dot", 4em))) -#let r3 = rect(stroke: (paint: cmyk(1%, 2%, 3%, 4%), thickness: 4em + 2pt, cap: "round", join: "bevel", dash: (array: (3pt, "dot", 4em), phase: 5em))) -#let s1 = r1.stroke -#let s2 = r2.stroke -#let s3 = r3.stroke -#test(s1.paint, cmyk(1%, 2%, 3%, 4%)) -#test(s1.thickness, 4em + 2pt) -#test(s1.cap, "round") -#test(s1.join, "bevel") -#test(s1.miter-limit, 5.0) -#test(s3.miter-limit, auto) -#test(s1.dash, none) -#test(s2.dash, (array: (3pt, "dot", 4em), phase: 0pt)) -#test(s3.dash, (array: (3pt, "dot", 4em), phase: 5em)) - ---- -// Test 2d alignment 'horizontal' field. -#test((start + top).x, start) -#test((end + top).x, end) -#test((left + top).x, left) -#test((right + top).x, right) -#test((center + top).x, center) -#test((start + bottom).x, start) -#test((end + bottom).x, end) -#test((left + bottom).x, left) -#test((right + bottom).x, right) -#test((center + bottom).x, center) -#test((start + horizon).x, start) -#test((end + horizon).x, end) -#test((left + horizon).x, left) -#test((right + horizon).x, right) -#test((center + horizon).x, center) -#test((top + start).x, start) -#test((bottom + end).x, end) -#test((horizon + center).x, center) - ---- -// Test 2d alignment 'vertical' field. -#test((start + top).y, top) -#test((end + top).y, top) -#test((left + top).y, top) -#test((right + top).y, top) -#test((center + top).y, top) -#test((start + bottom).y, bottom) -#test((end + bottom).y, bottom) -#test((left + bottom).y, bottom) -#test((right + bottom).y, bottom) -#test((center + bottom).y, bottom) -#test((start + horizon).y, horizon) -#test((end + horizon).y, horizon) -#test((left + horizon).y, horizon) -#test((right + horizon).y, horizon) -#test((center + horizon).y, horizon) -#test((top + start).y, top) -#test((bottom + end).y, bottom) -#test((horizon + center).y, horizon) - ---- -#{ - let object = sym.eq.not - // Error: 3-9 cannot mutate fields on symbol - object.property = "value" -} - ---- -#{ - let object = [hi] - // Error: 3-9 cannot mutate fields on content - object.property = "value" -} - ---- -#{ - let object = calc - // Error: 3-9 cannot mutate fields on module - object.property = "value" -} - ---- -#{ - let object = calc.sin - // Error: 3-9 cannot mutate fields on function - object.property = "value" -} - ---- -#{ - let object = none - // Error: 3-9 none does not have accessible fields - object.property = "value" -} - ---- -#{ - let object = 10 - // Error: 3-9 integer does not have accessible fields - object.property = "value" -} - ---- -#{ - let s = 1pt + red - // Error: 3-4 fields on stroke are not yet mutable - // Hint: 3-4 try creating a new stroke with the updated field value instead - s.thickness = 5pt -} diff --git a/tests/typ/compiler/for.typ b/tests/typ/compiler/for.typ deleted file mode 100644 index 392dd676..00000000 --- a/tests/typ/compiler/for.typ +++ /dev/null @@ -1,136 +0,0 @@ -// Test for loops. -// Ref: false - ---- -// Ref: true - -// Empty array. -#for x in () [Nope] - -// Dictionary is traversed in insertion order. -// Should output `Name: Typst. Age: 2.`. -#for (k, v) in (Name: "Typst", Age: 2) [ - #k: #v. -] - -// Block body. -// Should output `[1st, 2nd, 3rd, 4th]`. -#{ - "[" - for v in (1, 2, 3, 4) { - if v > 1 [, ] - [#v] - if v == 1 [st] - if v == 2 [nd] - if v == 3 [rd] - if v >= 4 [th] - } - "]" -} - -// Content block body. -// Should output `2345`. -#for v in (1, 2, 3, 4, 5, 6, 7) [#if v >= 2 and v <= 5 { repr(v) }] - -// Map captured arguments. -#let f1(..args) = args.pos().map(repr) -#let f2(..args) = args.named().pairs().map(p => repr(p.first()) + ": " + repr(p.last())) -#let f(..args) = (f1(..args) + f2(..args)).join(", ") -#f(1, a: 2) - ---- -#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").enumerate() { - test(repr(i + 1), v) -} - -// Pairs 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, ("a", 4), ("b", 5), "a", 6, "b", 7)) - -// Grapheme clusters 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" []), content) - ---- -// Uniterable expression. -// Error: 11-15 cannot loop over boolean -#for v in true {} - ---- -// Keys and values of strings. -// Error: 6-12 cannot destructure values of string -#for (k, v) in "hi" { - dont-care -} - ---- -// Destructuring without parentheses. -// Error: 7-8 unexpected comma -// Hint: 7-8 destructuring patterns must be wrapped in parentheses -#for k, v in (a: 4, b: 5) { - dont-care -} - -// Error: 7-8 unexpected comma -// Hint: 7-8 destructuring patterns must be wrapped in parentheses -#for k, in () {} - ---- -// Error: 5 expected pattern -#for - -// Error: 5 expected pattern -#for// - -// Error: 6 expected pattern -#{for} - -// Error: 7 expected keyword `in` -#for v - -// Error: 10 expected expression -#for v in - -// Error: 15 expected block -#for v in iter - -// Error: 5 expected pattern -#for -v in iter {} - -// Error: 7-10 expected pattern, found string -// Error: 16 expected block -A#for "v" thing - -// Error: 6-9 expected pattern, found string -#for "v" in iter {} - -// Error: 7 expected keyword `in` -#for a + b in iter {} diff --git a/tests/typ/compiler/highlight.typ b/tests/typ/compiler/highlight.typ deleted file mode 100644 index 1cbeaf9d..00000000 --- a/tests/typ/compiler/highlight.typ +++ /dev/null @@ -1,42 +0,0 @@ -#set page(width: auto) - -```typ -#set hello() -#set hello() -#set hello.world() -#set hello.my.world() -#let foo(x) = x * 2 -#show heading: func -#show module.func: func -#show module.func: it => {} -#foo(ident: ident) -#hello -#hello() -#box[] -#hello.world -#hello.world() -#hello().world() -#hello.my.world -#hello.my.world() -#hello.my().world -#hello.my().world() -#{ hello } -#{ hello() } -#{ hello.world() } -$ hello $ -$ hello() $ -$ box[] $ -$ hello.world $ -$ hello.world() $ -$ hello.my.world() $ -$ f_zeta(x), f_zeta(x)/1 $ -$ emph(hello.my.world()) $ -$ emph(hello.my().world) $ -$ emph(hello.my().world()) $ -$ #hello $ -$ #hello() $ -$ #hello.world $ -$ #hello.world() $ -$ #box[] $ -#if foo [] -``` diff --git a/tests/typ/compiler/hint.typ b/tests/typ/compiler/hint.typ deleted file mode 100644 index 1a5efcaa..00000000 --- a/tests/typ/compiler/hint.typ +++ /dev/null @@ -1,41 +0,0 @@ -// Test hints on diagnostics. -// Ref: false - ---- -// Error: 1:17-1:19 expected length, found integer: a length needs a unit - did you mean 12pt? -#set text(size: 12) - ---- -#{ - let a = 2 - a = 1-a - a = a -1 - - // Error: 7-10 unknown variable: a-1 - // Hint: 7-10 if you meant to use subtraction, try adding spaces around the minus sign - a = a-1 -} - ---- -#{ - // Error: 3-6 unknown variable: a-1 - // Hint: 3-6 if you meant to use subtraction, try adding spaces around the minus sign - a-1 = 2 -} - ---- -= Heading <intro> - -// Error: 1:20-1:26 cannot reference heading without numbering -// Hint: 1:20-1:26 you can enable heading numbering with `#set heading(numbering: "1.")` -Can not be used as @intro - ---- -// This test is more of a tooling test. It checks if hint annotation validation -// can be turned off. -// Hints: false - -= Heading <intro> - -// Error: 1:20-1:26 cannot reference heading without numbering -Can not be used as @intro diff --git a/tests/typ/compiler/if.typ b/tests/typ/compiler/if.typ deleted file mode 100644 index 1d2ed88b..00000000 --- a/tests/typ/compiler/if.typ +++ /dev/null @@ -1,136 +0,0 @@ -// Test if-else expressions. - ---- -// Test condition evaluation. -#if 1 < 2 [ - One. -] - -#if true == false [ - {Bad}, but we {dont-care}! -] - ---- -// Braced condition. -#if {true} [ - One. -] - -// Content block in condition. -#if [] != none [ - Two. -] - -// Multi-line condition with parens. -#if ( - 1 + 1 - == 1 -) [ - Nope. -] else { - "Three." -} - -// Multiline. -#if false [ - Bad. -] else { - let point = "." - "Four" + point -} - -// Content block can be argument or body depending on whitespace. -#{ - if content == type[b] [Fi] else [Nope] - if content == type [Nope] else [ve.] -} - -#let i = 3 -#if i < 2 [ - Five. -] else if i < 4 [ - Six. -] else [ - Seven. -] - ---- -// Test else if. -// Ref: false - -#let nth(n) = { - str(n) - if n == 1 { "st" } - else if n == 2 { "nd" } - else if n == 3 { "rd" } - else { "th" } -} - -#test(nth(1), "1st") -#test(nth(2), "2nd") -#test(nth(3), "3rd") -#test(nth(4), "4th") -#test(nth(5), "5th") - ---- -// Value of if expressions. -// Ref: false - -#{ - let x = 1 - let y = 2 - let z - - // Returns if branch. - z = if x < y { "ok" } - test(z, "ok") - - // Returns else branch. - z = if x > y { "bad" } else { "ok" } - test(z, "ok") - - // Missing else evaluates to none. - z = if x > y { "bad" } - test(z, none) -} - ---- -// 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" {} - ---- -// Error: 4 expected expression -#if - -// Error: 5 expected expression -#{if} - -// Error: 6 expected block -#if x - -// Error: 2-6 unexpected keyword `else` -#else {} - -// Should output `x`. -// Error: 4 expected expression -#if -x {} - -// Should output `something`. -// Error: 6 expected block -#if x something - -// Should output `A thing.` -// Error: 19 expected block -A#if false {} else thing - -#if a []else [b] -#if a [] else [b] -#if a {} else [b] diff --git a/tests/typ/compiler/import.typ b/tests/typ/compiler/import.typ deleted file mode 100644 index 5c3a05c9..00000000 --- a/tests/typ/compiler/import.typ +++ /dev/null @@ -1,262 +0,0 @@ -// Test function and module imports. -// Ref: false - ---- -// Test basic syntax and semantics. -// Ref: true - -// Test that this will be overwritten. -#let value = [foo] - -// Import multiple things. -#import "module.typ": fn, value -#fn[Like and Subscribe!] -#value - -// Should output `bye`. -// Stop at semicolon. -#import "module.typ": a, c;bye - ---- -// An item import. -#import "module.typ": item -#test(item(1, 2), 3) - -// Code mode -{ - import "module.typ": b - test(b, 1) -} - -// A wildcard import. -#import "module.typ": * - -// It exists now! -#test(d, 3) - ---- -// A renamed item import. -#import "module.typ": item as something -#test(something(1, 2), 3) - -// Mixing renamed and not renamed items. -#import "module.typ": fn, b as val, item as other -#test(val, 1) -#test(other(1, 2), 3) - ---- -// Test importing from function scopes. -// Ref: true - -#import enum: item -#import assert.with(true): * - -#enum( - item(1)[First], - item(5)[Fifth] -) -#eq(10, 10) -#ne(5, 6) - ---- -// Test renaming items imported from function scopes. -#import assert: eq as aseq -#aseq(10, 10) - ---- -// A module import without items. -#import "module.typ" -#test(module.b, 1) -#test(module.item(1, 2), 3) -#test(module.push(2), 3) - ---- -// A renamed module import without items. -#import "module.typ" as other -#test(other.b, 1) -#test(other.item(1, 2), 3) -#test(other.push(2), 3) - ---- -// Mixing renamed module and items. -#import "module.typ" as newname: b as newval, item -#test(newname.b, 1) -#test(newval, 1) -#test(item(1, 2), 3) -#test(newname.item(1, 2), 3) - ---- -// Renamed module import with function scopes. -#import enum as othernum -#test(enum, othernum) - ---- -// Mixing renamed module import from function with renamed item import. -#import assert as asrt -#import asrt: ne as asne -#asne(1, 2) - ---- -// Edge case for module access that isn't fixed. -#import "module.typ" - -// Works because the method name isn't categorized as mutating. -#test((module,).at(0).item(1, 2), 3) - -// Doesn't work because of mutating name. -// Error: 2-11 cannot mutate a temporary value -#(module,).at(0).push() - ---- -// Who needs whitespace anyways? -#import"module.typ":* - -// Allow the trailing comma. -#import "module.typ": a, c, - ---- -// Usual importing syntax also works for function scopes -#let d = (e: enum) -#import d.e -#import d.e as renamed -#import d.e: item -#item(2)[a] - ---- -// Warning: 23-27 unnecessary import rename to same name -#import enum: item as item - ---- -// Warning: 17-21 unnecessary import rename to same name -#import enum as enum - ---- -// Warning: 17-21 unnecessary import rename to same name -#import enum as enum: item -// Warning: 17-21 unnecessary import rename to same name -// Warning: 31-35 unnecessary import rename to same name -#import enum as enum: item as item - ---- -// No warning on a case that isn't obviously pathological -#import "module.typ" as module - ---- -// Can't import from closures. -#let f(x) = x -// Error: 9-10 cannot import from user-defined functions -#import f: x - ---- -// Can't import from closures, despite renaming. -#let f(x) = x -// Error: 9-10 cannot import from user-defined functions -#import f as g - ---- -// Can't import from closures, despite modifiers. -#let f(x) = x -// Error: 9-18 cannot import from user-defined functions -#import f.with(5): x - ---- -// Error: 9-18 cannot import from user-defined functions -#import () => {5}: x - ---- -// Error: 9-10 expected path, module, function, or type, found integer -#import 5: something - ---- -// Error: 9-10 expected path, module, function, or type, found integer -#import 5 as x - ---- -// Error: 9-11 failed to load file (is a directory) -#import "": name - ---- -// Error: 9-11 failed to load file (is a directory) -#import "" as x - ---- -// Error: 9-20 file not found (searched at typ/compiler/lib/0.2.1) -#import "lib/0.2.1" - ---- -// Error: 9-20 file not found (searched at typ/compiler/lib/0.2.1) -#import "lib/0.2.1" as x - ---- -// Some non-text stuff. -// Error: 9-35 file is not valid utf-8 -#import "/assets/images/rhino.png" - ---- -// Unresolved import. -// Error: 23-35 unresolved import -#import "module.typ": non_existing - ---- -// Cyclic import of this very file. -// Error: 9-23 cyclic import -#import "./import.typ" - ---- -// Cyclic import in other file. -#import "./modules/cycle1.typ": * - -This is never reached. - ---- -// Renaming does not import the old name (without items). -#import "module.typ" as something -// Error: 7-12 unknown variable: mymod -#test(mymod.b, 1) - ---- -// Renaming does not import the old name (with items). -#import "module.typ" as something: b as other -// Error: 7-12 unknown variable: mymod -#test(mymod.b, 1) - ---- -// Error: 8 expected expression -#import - ---- -// Error: 26-29 unexpected string -#import "module.typ": a, "b", c - ---- -// Error: 23-24 unexpected equals sign -#import "module.typ": = - ---- -// An additional trailing comma. -// Error: 31-32 unexpected comma -#import "module.typ": a, b, c,, - ---- -// Error: 2:2 expected semicolon or line break -#import "module.typ -"stuff - ---- -// A star in the list. -// Error: 26-27 unexpected star -#import "module.typ": a, *, b - ---- -// An item after a star. -// Error: 24 expected semicolon or line break -#import "module.typ": *, a - ---- -// Error: 14-15 unexpected colon -// Error: 16-17 unexpected integer -#import "": a: 1 - ---- -// Error: 14 expected comma -#import "": a b diff --git a/tests/typ/compiler/include.typ b/tests/typ/compiler/include.typ deleted file mode 100644 index 586e869b..00000000 --- a/tests/typ/compiler/include.typ +++ /dev/null @@ -1,32 +0,0 @@ -// Test module includes. - ---- -#set page(width: 200pt) - -= Document - -// Include a file -#include "modules/chap1.typ" - -// Expression as a file name. -#let chap2 = include "modu" + "les/chap" + "2.typ" - --- _Intermission_ -- -#chap2 - ---- -#{ - // Error: 19-38 file not found (searched at typ/compiler/modules/chap3.typ) - let x = include "modules/chap3.typ" -} - ---- -#include "modules/chap1.typ" - -// The variables of the file should not appear in this scope. -// Error: 2-6 unknown variable: name -#name - ---- -// Error: 18 expected semicolon or line break -#include "hi.typ" Hi diff --git a/tests/typ/compiler/label.typ b/tests/typ/compiler/label.typ deleted file mode 100644 index fabbac80..00000000 --- a/tests/typ/compiler/label.typ +++ /dev/null @@ -1,72 +0,0 @@ -// Test labels. - ---- -// Test labelled headings. -#show heading: set text(10pt) -#show heading.where(label: <intro>): underline - -= Introduction <intro> -The beginning. - -= Conclusion -The end. - ---- -// Test label after expression. -#show strong.where(label: <v>): set text(red) - -#let a = [*A*] -#let b = [*B*] -#a <v> #b - ---- -// Test labelled text. -#show "t": it => { - set text(blue) if it.has("label") and it.label == <last> - it -} - -This is a thing #[that <last>] happened. - ---- -// Test abusing dynamic labels for styling. -#show <red>: set text(red) -#show <blue>: set text(blue) - -*A* *B* <red> *C* #label("bl" + "ue") *D* - ---- -// Test that label ignores parbreak. -#show <hide>: none - -_Hidden_ -<hide> - -_Hidden_ - -<hide> -_Visible_ - ---- -// Test that label only works within one content block. -#show <strike>: strike -*This is* #[<strike>] *protected.* -*This is not.* <strike> - ---- -// Test that incomplete label is text. -1 < 2 is #if 1 < 2 [not] a label. - ---- -// Test label on text, styled, and sequence. -// Ref: false -#test([Hello<hi>].label, <hi>) -#test([#[A *B* C]<hi>].label, <hi>) -#test([#text(red)[Hello]<hi>].label, <hi>) - ---- -// Test getting the name of a label. -// Ref: false -#test(str(<hey>), "hey") -#test(str(label("hey")), "hey") -#test(str([Hmm<hey>].label), "hey") diff --git a/tests/typ/compiler/let.typ b/tests/typ/compiler/let.typ deleted file mode 100644 index 411509ff..00000000 --- a/tests/typ/compiler/let.typ +++ /dev/null @@ -1,302 +0,0 @@ -// Test let bindings. - ---- -// Automatically initialized with none. -#let x -#test(x, none) - -// Manually initialized with one. -#let z = 1 -#test(z, 1) - -// Syntax sugar for function definitions. -#let fill = conifer -#let f(body) = rect(width: 2cm, fill: fill, inset: 5pt, body) -#f[Hi!] - ---- -// Termination. - -// Terminated by line break. -#let v1 = 1 -One - -// Terminated by semicolon. -#let v2 = 2; Two - -// Terminated by semicolon and line break. -#let v3 = 3; -Three - -#test(v1, 1) -#test(v2, 2) -#test(v3, 3) - ---- -// Test what constitutes a valid Typst identifier. -// Ref: false -#let name = 1 -#test(name, 1) -#let name_ = 1 -#test(name_, 1) -#let name-2 = 1 -#test(name-2, 1) -#let name_2 = 1 -#test(name_2, 1) -#let __name = 1 -#test(__name, 1) -#let ůñıćóðė = 1 -#test(ůñıćóðė, 1) - ---- -// Test parenthesised assignments. -// Ref: false -#let (a) = (1, 2) - ---- -// Ref: false -// Simple destructuring. -#let (a, b) = (1, 2) -#test(a, 1) -#test(b, 2) - ---- -// Ref: false -#let (a,) = (1,) -#test(a, 1) - ---- -// Ref: false -// Destructuring with multiple placeholders. -#let (a, _, c, _) = (1, 2, 3, 4) -#test(a, 1) -#test(c, 3) - ---- -// Ref: false -// Destructuring with a sink. -#let (a, b, ..c) = (1, 2, 3, 4, 5, 6) -#test(a, 1) -#test(b, 2) -#test(c, (3, 4, 5, 6)) - ---- -// Ref: false -// Destructuring with a sink in the middle. -#let (a, ..b, c) = (1, 2, 3, 4, 5, 6) -#test(a, 1) -#test(b, (2, 3, 4, 5)) -#test(c, 6) - ---- -// Ref: false -// Destructuring with an empty sink. -#let (..a, b, c) = (1, 2) -#test(a, ()) -#test(b, 1) -#test(c, 2) - ---- -// Ref: false -// Destructuring with an empty sink. -#let (a, ..b, c) = (1, 2) -#test(a, 1) -#test(b, ()) -#test(c, 2) - ---- -// Ref: false -// Destructuring with an empty sink. -#let (a, b, ..c) = (1, 2) -#test(a, 1) -#test(b, 2) -#test(c, ()) - ---- -// Ref: false -// Destructuring with an empty sink and empty array. -#let (..a) = () -#test(a, ()) - ---- -// Ref: false -// Destructuring with unnamed sink. -#let (a, .., b) = (1, 2, 3, 4) -#test(a, 1) -#test(b, 4) - -// Error: 10-11 duplicate binding: a -#let (a, a) = (1, 2) - -// Error: 12-15 only one destructuring sink is allowed -#let (..a, ..a) = (1, 2) - -// Error: 12-13 duplicate binding: a -#let (a, ..a) = (1, 2) - -// Error: 13-14 duplicate binding: a -#let (a: a, a) = (a: 1, b: 2) - -// Error: 13-20 expected pattern, found function call -#let (a, b: b.at(0)) = (a: 1, b: 2) - -// Error: 7-14 expected pattern, found function call -#let (a.at(0),) = (1,) - ---- -// Error: 13-14 not enough elements to destructure -#let (a, b, c) = (1, 2) - ---- -// Error: 7-10 not enough elements to destructure -#let (..a, b, c, d) = (1, 2) - ---- -// Error: 6-12 cannot destructure boolean -#let (a, b) = true - ---- -// Ref: false -// Simple destructuring. -#let (a: a, b, x: c) = (a: 1, b: 2, x: 3) -#test(a, 1) -#test(b, 2) -#test(c, 3) - ---- -// Ref: false -// Destructuring with a sink. -#let (a: _, ..b) = (a: 1, b: 2, c: 3) -#test(b, (b: 2, c: 3)) - ---- -// Ref: false -// Destructuring with a sink in the middle. -#let (a: _, ..b, c: _) = (a: 1, b: 2, c: 3) -#test(b, (b: 2)) - ---- -// Ref: false -// Destructuring with an empty sink. -#let (a: _, ..b) = (a: 1) -#test(b, (:)) - ---- -// Ref: false -// Destructuring with an empty sink and empty dict. -#let (..a) = (:) -#test(a, (:)) - ---- -// Ref: false -// Destructuring with unnamed sink. -#let (a, ..) = (a: 1, b: 2) -#test(a, 1) - ---- -// Ref: false -// Nested destructuring. -#let ((a, b), (key: c)) = ((1, 2), (key: 3)) -#test((a, b, c), (1, 2, 3)) - ---- -// Keyed destructuring is not currently supported. -// Error: 7-18 expected pattern, found string -#let ("spacy key": val) = ("spacy key": 123) -#val - ---- -// Keyed destructuring is not currently supported. -#let x = "spacy key" -// Error: 7-10 expected identifier, found group -#let ((x): v) = ("spacy key": 123) - ---- -// Trailing placeholders. -// Error: 10-11 not enough elements to destructure -#let (a, _, _, _, _) = (1,) -#test(a, 1) - ---- -// Error: 10-13 expected pattern, found string -// Error: 18-19 expected pattern, found integer -#let (a: "a", b: 2) = (a: 1, b: 2) - ---- -// Error: 10-11 dictionary does not contain key "b" -#let (a, b) = (a: 1) - ---- -// Error: 10-11 dictionary does not contain key "b" -#let (a, b: b) = (a: 1) - ---- -// Error: 7-11 cannot destructure named pattern from an array -#let (a: a, b) = (1, 2, 3) - ---- -// Error: 5 expected pattern -#let - -// Error: 6 expected pattern -#{let} - -// Error: 6-9 expected pattern, found string -#let "v" - -// Error: 7 expected semicolon or line break -#let v 1 - -// Error: 9 expected expression -#let v = - -// Error: 6-9 expected pattern, 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: 18 expected expression -// Error: 11-12 unclosed delimiter -#let v5 = (1, 2 + ; Five - -// Error: 9-13 expected pattern, found boolean -#let (..true) = false - ---- -#let _ = 4 - -#for _ in range(2) [] - -// Error: 2-3 unexpected underscore -#_ - -// Error: 8-9 expected expression, found underscore -#lorem(_) - -// Error: 3-4 expected expression, found underscore -#(_,) - -// Error: 3-4 expected expression, found underscore -#{_} - -// Error: 8-9 expected expression, found underscore -#{ 1 + _ } - ---- -// Error: 13 expected equals sign -#let func(x) - -// Error: 15 expected expression -#let func(x) = - ---- -// Error: 12 expected equals sign -#let (func)(x) - ---- -// Error: 12 expected equals sign -// Error: 15-15 expected semicolon or line break -#let (func)(x) = 3 diff --git a/tests/typ/compiler/methods.typ b/tests/typ/compiler/methods.typ deleted file mode 100644 index 8d5484ed..00000000 --- a/tests/typ/compiler/methods.typ +++ /dev/null @@ -1,287 +0,0 @@ -// Test method calls. -// Ref: false - ---- -// Test whitespace around dot. -#test( "Hi there" . split() , ("Hi", "there")) - ---- -// Test mutating indexed value. -#{ - let matrix = (((1,), (2,)), ((3,), (4,))) - matrix.at(1).at(0).push(5) - test(matrix, (((1,), (2,)), ((3, 5), (4,)))) -} - ---- -// Test multiline chain in code block. -#{ - let rewritten = "Hello. This is a sentence. And one more." - .split(".") - .map(s => s.trim()) - .filter(s => s != "") - .map(s => s + "!") - .join("\n ") - - test(rewritten, "Hello!\n This is a sentence!\n And one more!") -} - ---- -// Test .at() default values for content. -#test(auto, [a].at("doesn't exist", default: auto)) - ---- -// Error: 2:10-2:13 type array has no method `fun` -#let numbers = () -#numbers.fun() - ---- -// Error: 2:4-2:10 type content has no method `stroke` -// Hint: 2:4-2:10 did you mean to access the field `stroke`? -#let l = line(stroke: red) -#l.stroke() - ---- -// Error: 2:2-2:43 cannot mutate a temporary value -#let numbers = (1, 2, 3) -#numbers.map(v => v / 2).sorted().map(str).remove(4) - ---- -// Error: 2:3-2:19 cannot mutate a temporary value -#let numbers = (1, 2, 3) -#(numbers.sorted() = 1) - ---- -// Error: 2-5 cannot mutate a constant: box -#box.push(1) - ---- -// Test content fields method. -#test([a].fields(), (text: "a")) -#test([a *b*].fields(), (children: ([a], [ ], strong[b]))) - ---- -// Test length unit conversions. -#test((500.934pt).pt(), 500.934) -#test((3.3453cm).cm(), 3.3453) -#test((4.3452mm).mm(), 4.3452) -#test((5.345in).inches(), 5.345) -#test((500.333666999pt).pt(), 500.333666999) -#test((3.5234354cm).cm(), 3.5234354) -#test((4.12345678mm).mm(), 4.12345678) -#test((5.333666999in).inches(), 5.333666999) -#test((4.123456789123456mm).mm(), 4.123456789123456) -#test((254cm).mm(), 2540.0) -#test(calc.round((254cm).inches(), digits: 2), 100.0) -#test((2540mm).cm(), 254.0) -#test(calc.round((2540mm).inches(), digits: 2), 100.0) -#test((100in).pt(), 7200.0) -#test(calc.round((100in).cm(), digits: 2), 254.0) -#test(calc.round((100in).mm(), digits: 2), 2540.0) -#test(5em.abs.cm(), 0.0) -#test((5em + 6in).abs.inches(), 6.0) - ---- -// Test length `to-absolute` method. -#set text(size: 12pt) -#context { - test((6pt).to-absolute(), 6pt) - test((6pt + 10em).to-absolute(), 126pt) - test((10em).to-absolute(), 120pt) -} - -#set text(size: 64pt) -#context { - test((6pt).to-absolute(), 6pt) - test((6pt + 10em).to-absolute(), 646pt) - test((10em).to-absolute(), 640pt) -} - ---- -// Error: 2-21 cannot convert a length with non-zero em units (`-6pt + 10.5em`) to pt -// Hint: 2-21 use `length.abs.pt()` instead to ignore its em component -#(10.5em - 6pt).pt() - ---- -// Error: 2-12 cannot convert a length with non-zero em units (`3em`) to cm -// Hint: 2-12 use `length.abs.cm()` instead to ignore its em component -#(3em).cm() - ---- -// Error: 2-20 cannot convert a length with non-zero em units (`-226.77pt + 93em`) to mm -// Hint: 2-20 use `length.abs.mm()` instead to ignore its em component -#(93em - 80mm).mm() - ---- -// Error: 2-24 cannot convert a length with non-zero em units (`432pt + 4.5em`) to inches -// Hint: 2-24 use `length.abs.inches()` instead to ignore its em component -#(4.5em + 6in).inches() - ---- -// Test color kind method. -#test(rgb(1, 2, 3, 4).space(), rgb) -#test(cmyk(4%, 5%, 6%, 7%).space(), cmyk) -#test(luma(40).space(), luma) -#test(rgb(1, 2, 3, 4).space() != luma, true) - ---- -// Test color '.components()' without conversions - -#let test-components(col, ref, has-alpha: true) = { - // Perform an approximate scalar comparison. - let are-equal((a, b)) = { - let to-float(x) = if type(x) == angle { x.rad() } else { float(x) } - let epsilon = 1e-4 // The maximum error between both numbers - assert.eq(type(a), type(b)) - calc.abs(to-float(a) - to-float(b)) < epsilon - } - - let ref-without-alpha = if has-alpha { ref.slice(0, -1) } else { ref } - assert.eq(col.components().len(), ref.len()) - assert(col.components().zip(ref).all(are-equal)) - assert(col.components(alpha: false).zip(ref-without-alpha).all(are-equal)) -} -#test-components(rgb(1, 2, 3, 4), (0.39%, 0.78%, 1.18%, 1.57%)) -#test-components(luma(40), (15.69%, 100%)) -#test-components(luma(40, 50%), (15.69%, 50%)) -#test-components(cmyk(4%, 5%, 6%, 7%), (4%, 5%, 6%, 7%), has-alpha: false) -#test-components(oklab(10%, 0.2, 0.4), (10%, 0.2, 0.4, 100%)) -#test-components(oklch(10%, 0.2, 90deg), (10%, 0.2, 90deg, 100%)) -#test-components(oklab(10%, 50%, 200%), (10%, 0.2, 0.8, 100%)) -#test-components(oklch(10%, 50%, 90deg), (10%, 0.2, 90deg, 100%)) -#test-components(color.linear-rgb(10%, 20%, 30%), (10%, 20%, 30%, 100%)) -#test-components(color.hsv(10deg, 20%, 30%), (10deg, 20%, 30%, 100%)) -#test-components(color.hsl(10deg, 20%, 30%), (10deg, 20%, 30%, 100%)) - ---- -// Test color conversions. -#test(rgb(1, 2, 3).to-hex(), "#010203") -#test(rgb(1, 2, 3, 4).to-hex(), "#01020304") -#test(luma(40).to-hex(), "#282828") -#test-repr(cmyk(4%, 5%, 6%, 7%).to-hex(), "#e0dcda") -#test-repr(rgb(cmyk(4%, 5%, 6%, 7%)), rgb(87.84%, 86.27%, 85.49%, 100%)) -#test-repr(rgb(luma(40%)), rgb(40%, 40%, 40%)) -#test-repr(cmyk(luma(40)), cmyk(11.76%, 10.67%, 10.51%, 14.12%)) -#test-repr(cmyk(rgb(1, 2, 3)), cmyk(66.67%, 33.33%, 0%, 98.82%)) -#test-repr(luma(rgb(1, 2, 3)), luma(0.73%)) -#test-repr(color.hsl(luma(40)), color.hsl(0deg, 0%, 15.69%)) -#test-repr(color.hsv(luma(40)), color.hsv(0deg, 0%, 15.69%)) -#test-repr(color.linear-rgb(luma(40)), color.linear-rgb(2.12%, 2.12%, 2.12%)) -#test-repr(color.linear-rgb(rgb(1, 2, 3)), color.linear-rgb(0.03%, 0.06%, 0.09%)) -#test-repr(color.hsl(rgb(1, 2, 3)), color.hsl(-150deg, 50%, 0.78%)) -#test-repr(color.hsv(rgb(1, 2, 3)), color.hsv(-150deg, 66.67%, 1.18%)) -#test-repr(oklab(luma(40)), oklab(27.68%, 0.0, 0.0, 100%)) -#test-repr(oklab(rgb(1, 2, 3)), oklab(8.23%, -0.004, -0.007, 100%)) -#test-repr(oklch(oklab(40%, 0.2, 0.2)), oklch(40%, 0.283, 45deg, 100%)) -#test-repr(oklch(luma(40)), oklch(27.68%, 0.0, 72.49deg, 100%)) -#test-repr(oklch(rgb(1, 2, 3)), oklch(8.23%, 0.008, 240.75deg, 100%)) - ---- -// Test gradient functions. -#test(gradient.linear(red, green, blue).kind(), gradient.linear) -#test(gradient.linear(red, green, blue).stops(), ((red, 0%), (green, 50%), (blue, 100%))) -#test(gradient.linear(red, green, blue, space: rgb).sample(0%), red) -#test(gradient.linear(red, green, blue, space: rgb).sample(25%), rgb("#97873b")) -#test(gradient.linear(red, green, blue, space: rgb).sample(50%), green) -#test(gradient.linear(red, green, blue, space: rgb).sample(75%), rgb("#17a08c")) -#test(gradient.linear(red, green, blue, space: rgb).sample(100%), blue) -#test(gradient.linear(red, green, space: rgb).space(), rgb) -#test(gradient.linear(red, green, space: oklab).space(), oklab) -#test(gradient.linear(red, green, space: oklch).space(), oklch) -#test(gradient.linear(red, green, space: cmyk).space(), cmyk) -#test(gradient.linear(red, green, space: luma).space(), luma) -#test(gradient.linear(red, green, space: color.linear-rgb).space(), color.linear-rgb) -#test(gradient.linear(red, green, space: color.hsl).space(), color.hsl) -#test(gradient.linear(red, green, space: color.hsv).space(), color.hsv) -#test(gradient.linear(red, green, relative: "self").relative(), "self") -#test(gradient.linear(red, green, relative: "parent").relative(), "parent") -#test(gradient.linear(red, green).relative(), auto) -#test(gradient.linear(red, green).angle(), 0deg) -#test(gradient.linear(red, green, dir: ltr).angle(), 0deg) -#test(gradient.linear(red, green, dir: rtl).angle(), 180deg) -#test(gradient.linear(red, green, dir: ttb).angle(), 90deg) -#test(gradient.linear(red, green, dir: btt).angle(), 270deg) -#test( - gradient.linear(red, green, blue).repeat(2).stops(), - ((red, 0%), (green, 25%), (blue, 50%), (red, 50%), (green, 75%), (blue, 100%)) -) -#test( - gradient.linear(red, green, blue).repeat(2, mirror: true).stops(), - ((red, 0%), (green, 25%), (blue, 50%), (green, 75%), (red, 100%)) -) - ---- -// Test alignment methods. -#test(start.axis(), "horizontal") -#test(end.axis(), "horizontal") -#test(left.axis(), "horizontal") -#test(right.axis(), "horizontal") -#test(center.axis(), "horizontal") -#test(top.axis(), "vertical") -#test(bottom.axis(), "vertical") -#test(horizon.axis(), "vertical") -#test(start.inv(), end) -#test(end.inv(), start) -#test(left.inv(), right) -#test(right.inv(), left) -#test(center.inv(), center) -#test(top.inv(), bottom) -#test(bottom.inv(), top) -#test(horizon.inv(), horizon) - ---- -// Test 2d alignment methods. -#test((start + top).inv(), (end + bottom)) -#test((end + top).inv(), (start + bottom)) -#test((left + top).inv(), (right + bottom)) -#test((right + top).inv(), (left + bottom)) -#test((center + top).inv(), (center + bottom)) -#test((start + bottom).inv(), (end + top)) -#test((end + bottom).inv(), (start + top)) -#test((left + bottom).inv(), (right + top)) -#test((right + bottom).inv(), (left + top)) -#test((center + bottom).inv(), (center + top)) -#test((start + horizon).inv(), (end + horizon)) -#test((end + horizon).inv(), (start + horizon)) -#test((left + horizon).inv(), (right + horizon)) -#test((right + horizon).inv(), (left + horizon)) -#test((center + horizon).inv(), (center + horizon)) -#test((top + start).inv(), (end + bottom)) -#test((bottom + end).inv(), (start + top)) -#test((horizon + center).inv(), (center + horizon)) - ---- -// Test direction methods. -#test(ltr.axis(), "horizontal") -#test(rtl.axis(), "horizontal") -#test(ttb.axis(), "vertical") -#test(btt.axis(), "vertical") -#test(ltr.start(), left) -#test(rtl.start(), right) -#test(ttb.start(), top) -#test(btt.start(), bottom) -#test(ltr.end(), right) -#test(rtl.end(), left) -#test(ttb.end(), bottom) -#test(btt.end(), top) -#test(ltr.inv(), rtl) -#test(rtl.inv(), ltr) -#test(ttb.inv(), btt) -#test(btt.inv(), ttb) - ---- -// Test angle methods. -#test(1rad.rad(), 1.0) -#test(1.23rad.rad(), 1.23) -#test(0deg.rad(), 0.0) -#test(2deg.deg(), 2.0) -#test(2.94deg.deg(), 2.94) -#test(0rad.deg(), 0.0) - ---- -// Test date methods. -#test(datetime(day: 1, month: 1, year: 2000).ordinal(), 1); -#test(datetime(day: 1, month: 3, year: 2000).ordinal(), 31 + 29 + 1); -#test(datetime(day: 31, month: 12, year: 2000).ordinal(), 366); -#test(datetime(day: 1, month: 3, year: 2001).ordinal(), 31 + 28 + 1); -#test(datetime(day: 31, month: 12, year: 2001).ordinal(), 365); diff --git a/tests/typ/compiler/module.typ b/tests/typ/compiler/module.typ deleted file mode 100644 index f0652677..00000000 --- a/tests/typ/compiler/module.typ +++ /dev/null @@ -1,13 +0,0 @@ -// A file to import in import / include tests. -// Ref: false - -#let a -#let b = 1 -#let c = 2 -#let d = 3 -#let value = [hi] -#let item(a, b) = a + b -#let push(a) = a + 1 -#let fn = rect.with(fill: conifer, inset: 5pt) - -Some _includable_ text. diff --git a/tests/typ/compiler/modules/chap1.typ b/tests/typ/compiler/modules/chap1.typ deleted file mode 100644 index 06a4c1a1..00000000 --- a/tests/typ/compiler/modules/chap1.typ +++ /dev/null @@ -1,9 +0,0 @@ -// Ref: false - -#let name = "Klaus" - -== Chapter 1 -#name stood in a field of wheat. There was nothing of particular interest about -the field #name just casually surveyed for any paths on which the corn would not -totally ruin his semi-new outdorsy jacket but then again, most of us spend -considerable time in non-descript environments. diff --git a/tests/typ/compiler/modules/chap2.typ b/tests/typ/compiler/modules/chap2.typ deleted file mode 100644 index d4aedc60..00000000 --- a/tests/typ/compiler/modules/chap2.typ +++ /dev/null @@ -1,11 +0,0 @@ -// Ref: false - -#let name = "Klaus" - -== Chapter 2 -Their motivations, however, were pretty descript, so to speak. #name had not yet -conceptualized their consequences, but that should change pretty quickly. #name -approached the center of the field and picked up a 4-foot long disk made from -what could only be cow manure. The hair on the back of #name' neck bristled as -he stared at the unusual sight. After studying the object for a while, he -promptly popped the question, "How much?" diff --git a/tests/typ/compiler/modules/cycle1.typ b/tests/typ/compiler/modules/cycle1.typ deleted file mode 100644 index 02067b71..00000000 --- a/tests/typ/compiler/modules/cycle1.typ +++ /dev/null @@ -1,6 +0,0 @@ -// Ref: false - -#import "cycle2.typ": * -#let inaccessible = "wow" - -This is the first element of an import cycle. diff --git a/tests/typ/compiler/modules/cycle2.typ b/tests/typ/compiler/modules/cycle2.typ deleted file mode 100644 index 191647db..00000000 --- a/tests/typ/compiler/modules/cycle2.typ +++ /dev/null @@ -1,6 +0,0 @@ -// Ref: false - -#import "cycle1.typ": * -#let val = "much cycle" - -This is the second element of an import cycle. diff --git a/tests/typ/compiler/ops-assoc.typ b/tests/typ/compiler/ops-assoc.typ deleted file mode 100644 index ec128c61..00000000 --- a/tests/typ/compiler/ops-assoc.typ +++ /dev/null @@ -1,18 +0,0 @@ -// Test operator associativity. -// Ref: false - ---- -// Math operators are left-associative. -#test(10 / 2 / 2 == (10 / 2) / 2, true) -#test(10 / 2 / 2 == 10 / (2 / 2), false) -#test(1 / 2 * 3, 1.5) - ---- -// Assignment is right-associative. -{ - let x = 1 - let y = 2 - x = y = "ok" - test(x, none) - test(y, "ok") -} diff --git a/tests/typ/compiler/ops-invalid.typ b/tests/typ/compiler/ops-invalid.typ deleted file mode 100644 index 64e3a878..00000000 --- a/tests/typ/compiler/ops-invalid.typ +++ /dev/null @@ -1,134 +0,0 @@ -// Test invalid operations. -// Ref: false - ---- -// Error: 4 expected expression -#(-) - ---- -// Error: 10 expected expression -#test({1+}, 1) - ---- -// Error: 10 expected expression -#test({2*}, 2) - ---- -// Error: 3-13 cannot apply unary '+' to content -#(+([] + [])) - ---- -// Error: 3-6 cannot apply '-' to string -#(-"") - ---- -// Error: 3-9 cannot apply 'not' to array -#(not ()) - ---- -// Error: 3-19 cannot compare relative length and ratio -#(30% + 1pt <= 40%) - ---- -// Error: 3-14 cannot compare 1em with 10pt -#(1em <= 10pt) - ---- -// Error: 3-22 cannot compare 2.2 with NaN -#(2.2 <= float("nan")) - ---- -// Error: 3-26 cannot compare integer and string -#((0, 1, 3) > (0, 1, "a")) - ---- -// Error: 3-42 cannot compare 3.5 with NaN -#((0, "a", 3.5) <= (0, "a", float("nan"))) - ---- -// Error: 3-12 cannot divide by zero -#(1.2 / 0.0) - ---- -// Error: 3-8 cannot divide by zero -#(1 / 0) - ---- -// Error: 3-15 cannot divide by zero -#(15deg / 0deg) - ---- -// Special messages for +, -, * and /. -// Error: 3-10 cannot add integer and string -#(1 + "2", 40% - 1) - ---- -// Error: 15-23 cannot add integer and string -#{ let x = 1; x += "2" } - ---- -// Error: 4-13 cannot divide ratio by length -#( 10% / 5pt ) - ---- -// Error: 3-12 cannot divide these two lengths -#(1em / 5pt) - ---- -// Error: 3-19 cannot divide relative length by ratio -#((10% + 1pt) / 5%) - ---- -// Error: 3-28 cannot divide these two relative lengths -#((10% + 1pt) / (20% + 1pt)) - ---- -// Error: 13-20 cannot subtract integer from ratio -#((1234567, 40% - 1)) - ---- -// Error: 3-11 cannot multiply integer with boolean -#(2 * true) - ---- -// Error: 3-11 cannot divide integer by length -#(3 / 12pt) - ---- -// Error: 3-10 number must be at least zero -#(-1 * "") - ---- -// Error: 4-5 unknown variable: x -#((x) = "") - ---- -// Error: 4-5 unknown variable: x -#((x,) = (1,)) - ---- -// Error: 3-8 cannot mutate a temporary value -#(1 + 2 += 3) - ---- -// Error: 2:3-2:8 cannot apply 'not' to string -#let x = "Hey" -#(not x = "a") - ---- -// Error: 7-8 unknown variable: x -#(1 + x += 3) - ---- -// Error: 3-4 unknown variable: z -#(z = 1) - ---- -// Error: 3-7 cannot mutate a constant: rect -#(rect = "hi") - ---- -// Works if we define rect beforehand -// (since then it doesn't resolve to the standard library version anymore). -#let rect = "" -#(rect = "hi") diff --git a/tests/typ/compiler/ops-prec.typ b/tests/typ/compiler/ops-prec.typ deleted file mode 100644 index d3fe01b5..00000000 --- a/tests/typ/compiler/ops-prec.typ +++ /dev/null @@ -1,36 +0,0 @@ -// Test operator precedence. -// Ref: false - ---- -// Multiplication binds stronger than addition. -#test(1+2*-3, -5) - -// Subtraction binds stronger than comparison. -#test(3 == 5 - 2, true) - -// Boolean operations bind stronger than '=='. -#test("a" == "a" and 2 < 3, true) -#test(not "b" == "b", false) - ---- -// Assignment binds stronger than boolean operations. -// Error: 2:3-2:8 cannot mutate a temporary value -#let x = false -#(not x = "a") - ---- -// Precedence doesn't matter for chained unary operators. -// Error: 3-12 cannot apply '-' to boolean -#(-not true) - ---- -// Not in handles precedence. -#test(-1 not in (1, 2, 3), true) - ---- -// Parentheses override precedence. -#test((1), 1) -#test((1+2)*-3, -9) - -// Error: 8-9 unclosed delimiter -#test({(1 + 1}, 2) diff --git a/tests/typ/compiler/ops.typ b/tests/typ/compiler/ops.typ deleted file mode 100644 index e148dd19..00000000 --- a/tests/typ/compiler/ops.typ +++ /dev/null @@ -1,359 +0,0 @@ -// 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((0, 1, 2, 4) < (0, 1, 2, 5), true) -#test((0, 1, 2, 4) < (0, 1, 2, 3), false) -#test((0, 1, 2, 3.3) > (0, 1, 2, 4), false) -#test((0, 1, 2) < (0, 1, 2, 3), true) -#test((0, 1, "b") > (0, 1, "a", 3), true) -#test((0, 1.1, 3) >= (0, 1.1, 3), true) -#test((0, 1, datetime(day: 1, month: 12, year: 2023)) <= (0, 1, datetime(day: 1, month: 12, year: 2023), 3), true) -#test(("a", 23, 40, "b") > ("a", 23, 40), true) -#test(() <= (), true) -#test(() >= (), true) -#test(() <= (1,), true) -#test((1,) <= (), false) - ---- -// 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) - ---- -// Test comma placement in destructuring assignment. -#let array = (1, 2, 3) -#((key: array.at(1)) = (key: "hi")) -#test(array, (1, "hi", 3)) - -#let array = (1, 2, 3) -#((array.at(1)) = ("hi")) -#test(array, (1, "hi", 3)) - -#let array = (1, 2, 3) -#((array.at(1),) = ("hi",)) -#test(array, (1, "hi", 3)) - -#let array = (1, 2, 3) -#((array.at(1)) = ("hi",)) -#test(array, (1, ("hi",), 3)) - ---- -// Test nested destructuring assignment. -#let a -#let b -#let c -#(((a, b), (key: c)) = ((1, 2), (key: 3))) -#test((a, b, c), (1, 2, 3)) - ---- -#let array = (1, 2, 3) -// Error: 3-17 cannot destructure string -#((array.at(1),) = ("hi")) -#test(array, (1, ("hi",), 3)) - ---- -// 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, 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) - -// Apply arguments to an argument sink. -#let times(..sink) = { - let res = sink.pos().product() - if sink.named().at("negate", default: false) { res *= -1 } - res -} -#test((times.with(2, negate: true).with(5))(), -10) -#test((times.with(2).with(5).with(negate: true))(), -10) -#test((times.with(2).with(5, negate: true))(), -10) -#test((times.with(2).with(negate: true))(5), -10) diff --git a/tests/typ/compiler/packages.typ b/tests/typ/compiler/packages.typ deleted file mode 100644 index 0d3fda58..00000000 --- a/tests/typ/compiler/packages.typ +++ /dev/null @@ -1,69 +0,0 @@ -// Test package imports -// Ref: false - ---- -// Test import without items. -#import "@test/adder:0.1.0" -#test(adder.add(2, 8), 10) - ---- -// Test import with items. -#import "@test/adder:0.1.0": add -#test(add(2, 8), 10) - ---- -// Test too high required compiler version. -// Error: 9-29 package requires typst 1.0.0 or newer (current version is VERSION) -#import "@test/future:0.1.0": future - ---- -// Error: 9-13 `@` is not a valid package namespace -#import "@@": * - ---- -// Error: 9-16 package specification is missing name -#import "@heya": * - ---- -// Error: 9-15 `123` is not a valid package namespace -#import "@123": * - ---- -// Error: 9-17 package specification is missing name -#import "@test/": * - ---- -// Error: 9-22 package specification is missing version -#import "@test/mypkg": * - ---- -// Error: 9-20 `$$$` is not a valid package name -#import "@test/$$$": * - ---- -// Error: 9-23 package specification is missing version -#import "@test/mypkg:": * - ---- -// Error: 9-24 version number is missing minor version -#import "@test/mypkg:0": * - ---- -// Error: 9-29 `latest` is not a valid major version -#import "@test/mypkg:latest": * - ---- -// Error: 9-29 `-3` is not a valid major version -#import "@test/mypkg:-3.0.0": * - ---- -// Error: 9-26 version number is missing patch version -#import "@test/mypkg:0.3": * - ---- -// Error: 9-27 version number is missing patch version -#import "@test/mypkg:0.3.": * - ---- -// Error: 9-28 file not found (searched at typ/compiler/#test/mypkg:1.0.0) -#import "#test/mypkg:1.0.0": * diff --git a/tests/typ/compiler/plugin-oob.typ b/tests/typ/compiler/plugin-oob.typ deleted file mode 100644 index 4d1ba205..00000000 --- a/tests/typ/compiler/plugin-oob.typ +++ /dev/null @@ -1,14 +0,0 @@ -// Test Out Of Bound read/write in WebAssembly plugins communication. -// Ref: false - ---- -#let p = plugin("/assets/plugins/plugin-oob.wasm") - -// Error: 2-14 plugin tried to read out of bounds: pointer 0x40000000 is out of bounds for read of length 1 -#p.read_oob() - ---- -#let p = plugin("/assets/plugins/plugin-oob.wasm") - -// Error: 2-27 plugin tried to write out of bounds: pointer 0x40000000 is out of bounds for write of length 3 -#p.write_oob(bytes("xyz")) diff --git a/tests/typ/compiler/plugin.typ b/tests/typ/compiler/plugin.typ deleted file mode 100644 index e727355f..00000000 --- a/tests/typ/compiler/plugin.typ +++ /dev/null @@ -1,36 +0,0 @@ -// Test WebAssembly plugins. -// Ref: false - ---- -#let p = plugin("/assets/plugins/hello.wasm") -#test(p.hello(), bytes("Hello from wasm!!!")) -#test(p.double_it(bytes("hey!")), bytes("hey!.hey!")) -#test( - p.shuffle(bytes("value1"), bytes("value2"), bytes("value3")), - bytes("value3-value1-value2"), -) - ---- -#let p = plugin("/assets/plugins/hello.wasm") - -// Error: 2-20 plugin function takes 0 arguments, but 1 was given -#p.hello(bytes("")) - ---- -#let p = plugin("/assets/plugins/hello.wasm") - -// Error: 10-14 expected bytes, found boolean -// Error: 27-29 expected bytes, found integer -#p.hello(true, bytes(()), 10) - ---- -#let p = plugin("/assets/plugins/hello.wasm") - -// Error: 2-17 plugin errored with: This is an `Err` -#p.returns_err() - ---- -#let p = plugin("/assets/plugins/hello.wasm") - -// Error: 2-16 plugin panicked: wasm `unreachable` instruction executed -#p.will_panic() diff --git a/tests/typ/compiler/raw.typ b/tests/typ/compiler/raw.typ deleted file mode 100644 index 3084146d..00000000 --- a/tests/typ/compiler/raw.typ +++ /dev/null @@ -1,170 +0,0 @@ -// Test new raw parser -// Ref: false - ---- -#let empty = ( - name: "empty", - input: ``, - text: "", -) - -#let backtick = ( - name: "backtick", - input: ``` ` ```, - text: "`", - block: false, -) - -#let lang-backtick = ( - name: "lang-backtick", - input: ```js ` ```, - lang: "js", - text: "`", - block: false, -) - -// The language tag stops on space -#let lang-space = ( - name: "lang-space", - input: ```js test ```, - lang: "js", - text: "test ", - block: false, -) - -// The language tag stops on newline -#let lang-newline = ( - name: "lang-newline", - input: ```js -test -```, - lang: "js", - text: "test", - block: true, -) - -// The first line and the last line are ignored -#let blocky = ( - name: "blocky", - input: { -``` -test -``` -}, - text: "test", - block: true, -) - -// A blocky raw should handle dedents -#let blocky-dedent = ( - name: "blocky-dedent", - input: { -``` - test - ``` - }, - text: "test", - block: true, -) - -// When there is content in the first line, it should exactly eat a whitespace char. -#let blocky-dedent-firstline = ( - name: "blocky-dedent-firstline", - input: ``` test - ```, - text: "test", - block: true, -) - -// When there is content in the first line, it should exactly eat a whitespace char. -#let blocky-dedent-firstline2 = ( - name: "blocky-dedent-firstline2", - input: ``` test -```, - text: "test", - block: true, -) - -// The first line is not affected by dedent, and the middle lines don't consider the whitespace prefix of the first line. -#let blocky-dedent-firstline3 = ( - name: "blocky-dedent-firstline3", - input: ``` test - test2 - ```, - text: "test\n test2", - block: true, -) - -// The first line is not affected by dedent, and the middle lines don't consider the whitespace prefix of the first line. -#let blocky-dedent-firstline4 = ( - name: "blocky-dedent-firstline4", - input: ``` test - test2 - ```, - text: " test\ntest2", - block: true, -) - -#let blocky-dedent-lastline = ( - name: "blocky-dedent-lastline", - input: ``` - test - ```, - text: " test", - block: true, -) - -#let blocky-dedent-lastline2 = ( - name: "blocky-dedent-lastline2", - input: ``` - test - ```, - text: "test", - block: true, -) - -#let blocky-tab = ( - name: "blocky-tab", - input: { -``` - test -``` -}, - text: "\ttest", - block: true, -) - -#let blocky-tab-dedent = ( - name: "blocky-tab-dedent", - input: { -``` - test - - ``` -}, - text: "test\n ", - block: true, -) - -#let cases = ( - empty, - backtick, - lang-backtick, - lang-space, - lang-newline, - blocky, - blocky-dedent, - blocky-dedent-firstline, - blocky-dedent-firstline2, - blocky-dedent-firstline3, - blocky-dedent-lastline, - blocky-dedent-lastline2, - blocky-tab, - blocky-tab-dedent, -) - -#for c in cases { - assert.eq(c.text, c.input.text, message: "in point " + c.name + ", expect " + repr(c.text) + ", got " + repr(c.input.text) + "") - let block = c.at("block", default: false) - assert.eq(block, c.input.block, message: "in point " + c.name + ", expect " + repr(block) + ", got " + repr(c.input.block) + "") -} diff --git a/tests/typ/compiler/recursion.typ b/tests/typ/compiler/recursion.typ deleted file mode 100644 index 421b638b..00000000 --- a/tests/typ/compiler/recursion.typ +++ /dev/null @@ -1,56 +0,0 @@ -// Test recursive function calls. -// Ref: false - ---- -// Test with named function. -#let fib(n) = { - if n <= 2 { - 1 - } else { - fib(n - 1) + fib(n - 2) - } -} - -#test(fib(10), 55) - ---- -// Test with unnamed function. -// Error: 17-18 unknown variable: f -#let f = (n) => f(n - 1) -#f(10) - ---- -// Test capturing with named function. -#let f = 10 -#let f() = f -#test(type(f()), function) - ---- -// Test capturing with unnamed function. -#let f = 10 -#let f = () => f -#test(type(f()), int) - ---- -// Test redefinition. -#let f(x) = "hello" -#let f(x) = if x != none { f(none) } else { "world" } -#test(f(1), "world") - ---- -// Error: 15-21 maximum function call depth exceeded -#let rec(n) = rec(n) + 1 -#rec(1) - ---- -// Test cyclic imports during layout. -// Error: 2-38 maximum show rule depth exceeded -// Hint: 2-38 check whether the show rule matches its own output -#layout(_ => include "recursion.typ") - ---- -// Test recursive show rules. -// Error: 22-25 maximum show rule depth exceeded -// Hint: 22-25 check whether the show rule matches its own output -#show math.equation: $x$ -$ x $ diff --git a/tests/typ/compiler/repr-color-gradient.typ b/tests/typ/compiler/repr-color-gradient.typ deleted file mode 100644 index ef158974..00000000 --- a/tests/typ/compiler/repr-color-gradient.typ +++ /dev/null @@ -1,23 +0,0 @@ -// Test representation of values in the document. - ---- -// Colors -#set page(width: 400pt) -#set text(0.8em) -#blue \ -#color.linear-rgb(blue) \ -#oklab(blue) \ -#oklch(blue) \ -#cmyk(blue) \ -#color.hsl(blue) \ -#color.hsv(blue) \ -#luma(blue) - ---- -// Gradients -#set page(width: 400pt) -#set text(0.8em) -#gradient.linear(blue, red) \ -#gradient.linear(blue, red, dir: ttb) \ -#gradient.linear(blue, red, angle: 45deg, relative: "self") \ -#gradient.linear(blue, red, angle: 45deg, space: rgb) diff --git a/tests/typ/compiler/repr.typ b/tests/typ/compiler/repr.typ deleted file mode 100644 index 13593a86..00000000 --- a/tests/typ/compiler/repr.typ +++ /dev/null @@ -1,49 +0,0 @@ -// Test representation of values in the document. - ---- -// Literal values. -#auto \ -#none (empty) \ -#true \ -#false - ---- -// Numerical values. -#1 \ -#1.0e-4 \ -#3.15 \ -#1e-10 \ -#50.368% \ -#0.0000012345pt \ -#4.5cm \ -#12e1pt \ -#2.5rad \ -#45deg \ -#1.7em \ -#(1cm + 0em) \ -#(2em + 10pt) \ -#2.3fr - ---- -// Colors and strokes. -#set text(0.8em) -#rgb("f7a205") \ -#(2pt + rgb("f7a205")) - -// Strings and escaping. -#raw(repr("hi"), lang: "typc") -#repr("a\n[]\"\u{1F680}string") - -// Content. -#raw(lang: "typc", repr[*Hey*]) - -// Functions. -#let f(x) = x -#f \ -#rect \ -#(() => none) - -// Types. -#int \ -#type("hi") \ -#type((a: 1)) diff --git a/tests/typ/compiler/return.typ b/tests/typ/compiler/return.typ deleted file mode 100644 index e709d6a7..00000000 --- a/tests/typ/compiler/return.typ +++ /dev/null @@ -1,89 +0,0 @@ -// Test return out of functions. -// Ref: false - ---- -// Test return with value. -#let f(x) = { - return x + 1 -} - -#test(f(1), 2) - ---- -// Test return with joining. - -#let f(x) = { - "a" - if x == 0 { - return "b" - } else if x == 1 { - "c" - } else { - "d" - return - "e" - } -} - -#test(f(0), "b") -#test(f(1), "ac") -#test(f(2), "ad") - ---- -// Test return with joining and content. -// Ref: true - -#let f(text, caption: none) = { - text - if caption == none [\.#return] - [, ] - emph(caption) - [\.] -} - -#f(caption: [with caption])[My figure] - -#f[My other figure] - ---- -// Test return outside of function. - -#for x in range(5) { - // Error: 3-9 cannot return outside of function - return -} - ---- -// Test that the expression is evaluated to the end. -#let sum(..args) = { - let s = 0 - for v in args.pos() { - s += v - } - s -} - -#let f() = { - sum(..return, 1, 2, 3) - "nope" -} - -#test(f(), 6) - ---- -// Test value return from content. -#let x = 3 -#let f() = [ - Hello 😀 - #return "nope" - World -] - -#test(f(), "nope") - ---- -// Test rejection of extra value -#let f() = [ - // Error: 16-16 expected semicolon or line break - #return a + b Hello World -] diff --git a/tests/typ/compiler/select-where-styles.typ b/tests/typ/compiler/select-where-styles.typ deleted file mode 100644 index 028be2e9..00000000 --- a/tests/typ/compiler/select-where-styles.typ +++ /dev/null @@ -1,91 +0,0 @@ -// Test that where selectors also work with settable fields. - ---- -// Test that where selectors also trigger on set rule fields. -#show raw.where(block: false): box.with( - fill: luma(220), - inset: (x: 3pt, y: 0pt), - outset: (y: 3pt), - radius: 2pt, -) - -This is #raw("fn main() {}") some text. - ---- -// Note: This show rule is horribly inefficient because it triggers for -// every individual text element. But it should still work. -#show text.where(lang: "de"): set text(red) - -#set text(lang: "es") -Hola, mundo! - -#set text(lang: "de") -Hallo Welt! - -#set text(lang: "en") -Hello World! - ---- -// Test that folding is taken into account. -#set text(5pt) -#set text(2em) - -#[ - #show text.where(size: 2em): set text(blue) - 2em not blue -] - -#[ - #show text.where(size: 10pt): set text(blue) - 10pt blue -] - ---- -// Test again that folding is taken into account. -#set rect(width: 40pt, height: 10pt) -#set rect(stroke: blue) -#set rect(stroke: 2pt) - -#{ - show rect.where(stroke: blue): "Not Triggered" - rect() -} -#{ - show rect.where(stroke: 2pt): "Not Triggered" - rect() -} -#{ - show rect.where(stroke: 2pt + blue): "Triggered" - rect() -} - ---- -// Test that resolving is *not* taken into account. -#set line(start: (1em, 1em + 2pt)) - -#{ - show line.where(start: (1em, 1em + 2pt)): "Triggered" - line() -} -#{ - show line.where(start: (10pt, 12pt)): "Not Triggered" - line() -} - - ---- -// Test again that resolving is *not* taken into account. -#set text(hyphenate: auto) - -#[ - #show text.where(hyphenate: auto): underline - Auto -] -#[ - #show text.where(hyphenate: true): underline - True -] -#[ - #show text.where(hyphenate: false): underline - False -] diff --git a/tests/typ/compiler/selector-logical.typ b/tests/typ/compiler/selector-logical.typ deleted file mode 100644 index 5369e4c7..00000000 --- a/tests/typ/compiler/selector-logical.typ +++ /dev/null @@ -1,126 +0,0 @@ -//Tests for logical (and/or) selectors - ---- -= A -== B -#figure([Cat], kind: "cat", supplement: [Other]) -=== D -= E <first> -#figure([Frog], kind: "frog", supplement: none) -#figure([Giraffe], kind: "giraffe", supplement: none) <second> -#figure([GiraffeCat], kind: "cat", supplement: [Other]) <second> -= H -#figure([Iguana], kind: "iguana", supplement: none) -== I - -#let test-selector(selector, ref) = context { - test(query(selector).map(e => e.body), ref) -} - -// Test `or`. -#test-selector( - heading.where(level: 1).or(heading.where(level: 3)), - ([A], [D], [E], [H]), -) - -#test-selector( - heading.where(level: 1).or( - heading.where(level: 3), - figure.where(kind: "frog"), - ), - ([A], [D], [E], [Frog], [H]), -) - -#test-selector( - heading.where(level: 1).or( - heading.where(level: 2), - figure.where(kind: "frog"), - figure.where(kind: "cat"), - ), - ([A], [B], [Cat], [E], [Frog], [GiraffeCat], [H], [I]), -) - -#test-selector( - figure.where(kind: "dog").or(heading.where(level: 3)), - ([D],), -) - -#test-selector( - figure.where(kind: "dog").or(figure.where(kind: "fish")), - (), -) - -// Test `or` duplicates removal. -#test-selector( - heading.where(level: 1).or(heading.where(level: 1)), - ([A], [E], [H]), -) - -// Test `and`. -#test-selector( - figure.where(kind: "cat").and(figure.where(kind: "frog")), - (), -) - -// Test `or` with `before`/`after` -#test-selector( - selector(heading) - .before(<first>) - .or(selector(figure).before(<first>)), - ([A], [B], [Cat], [D], [E]), -) - -#test-selector( - heading.where(level: 2) - .after(<first>) - .or(selector(figure).after(<first>)), - ([Frog], [Giraffe], [GiraffeCat], [Iguana], [I]), -) - -// Test `and` with `after` -#test-selector( - figure.where(kind: "cat") - .and(figure.where(supplement: [Other])) - .after(<first>), - ([GiraffeCat],), -) - -// Test `and` (with nested `or`) -#test-selector( - heading.where(level: 2) - .or(heading.where(level: 3)) - .and(heading.where(level: 2).or(heading.where(level: 1))), - ([B], [I]), -) - -#test-selector( - heading.where(level: 2) - .or(heading.where(level: 3), heading.where(level:1)) - .and( - heading.where(level: 2).or(heading.where(level: 1)), - heading.where(level: 3).or(heading.where(level: 1)), - ), - ([A], [E], [H]), -) - -// Test `and` with `or` and `before`/`after` -#test-selector( - heading.where(level: 1).before(<first>) - .or(heading.where(level: 3).before(<first>)) - .and( - heading.where(level: 1).before(<first>) - .or(heading.where(level: 2).before(<first>)) - ), - ([A], [E]), -) - -#test-selector( - heading.where(level: 1).before(<first>, inclusive: false) - .or(selector(figure).after(<first>)) - .and(figure.where(kind: "iguana").or( - figure.where(kind: "frog"), - figure.where(kind: "cat"), - heading.where(level: 1).after(<first>), - )), - ([Frog], [GiraffeCat], [Iguana]) -) diff --git a/tests/typ/compiler/set.typ b/tests/typ/compiler/set.typ deleted file mode 100644 index 23b3a7c6..00000000 --- a/tests/typ/compiler/set.typ +++ /dev/null @@ -1,66 +0,0 @@ -// General tests for set. - ---- -// Test that text is affected by instantiation-site bold. -#let x = [World] -Hello *#x* - ---- -// Test that lists are affected by correct indents. -#let fruit = [ - - Apple - - Orange - #list(body-indent: 20pt)[Pear] -] - -- Fruit -#[#set list(indent: 10pt) - #fruit] -- No more fruit - ---- -// Test that that block spacing and text style are respected from -// the outside, but the more specific fill is respected. -#set block(spacing: 4pt) -#set text(style: "italic", fill: eastern) -#let x = [And the forest #parbreak() lay silent!] -#text(fill: forest, x) - ---- -// Test that scoping works as expected. -#{ - if true { - set text(blue) - [Blue ] - } - [Not blue] -} - ---- -// Test relative path resolving in layout phase. -#let choice = ("monkey.svg", "rhino.png", "tiger.jpg") -#set enum(numbering: n => { - let path = "/assets/images/" + choice.at(n - 1) - move(dy: -0.15em, image(path, width: 1em, height: 1em)) -}) - -+ Monkey -+ Rhino -+ Tiger - ---- -// Test conditional set. -#show ref: it => { - set text(red) if it.target == <unknown> - "@" + str(it.target) -} - -@hello from the @unknown - ---- -// Error: 19-24 expected boolean, found integer -#set text(red) if 1 + 2 - ---- -// Error: 12-26 set is only allowed directly in code and content blocks -#{ let x = set text(blue) } diff --git a/tests/typ/compiler/shorthand.typ b/tests/typ/compiler/shorthand.typ deleted file mode 100644 index 54ae7473..00000000 --- a/tests/typ/compiler/shorthand.typ +++ /dev/null @@ -1,61 +0,0 @@ -// Test shorthands for unicode codepoints. - ---- -The non-breaking space~does work, soft-?hyphen also does. - ---- -// Make sure non-breaking and normal space always -// have the same width. Even if the font decided -// differently. -#set text(font: "New Computer Modern") -a b \ -a~b - ---- -- En dash: -- -- Em dash: --- - ---- -#set text(font: "Roboto") -A... vs #"A..." - ---- -// Check all math shorthands -$...$\ -$-$\ -$'$\ -$*$\ -$!=$\ -$:=$\ -$::=$\ -$=:$\ -$<<$\ -$<<<$\ -$>>$\ -$>>>$\ -$<=$\ -$>=$\ -$->$\ -$-->$\ -$|->$\ -$>->$\ -$->>$\ -$<-$\ -$<--$\ -$<-<$\ -$<<-$\ -$<->$\ -$<-->$\ -$~>$\ -$~~>$\ -$<~$\ -$<~~$\ -$=>$\ -$|=>$\ -$==>$\ -$<==$\ -$<=>$\ -$<==>$\ -$[|$\ -$|]$\ -$||$ diff --git a/tests/typ/compiler/show-bare.typ b/tests/typ/compiler/show-bare.typ deleted file mode 100644 index 210f072d..00000000 --- a/tests/typ/compiler/show-bare.typ +++ /dev/null @@ -1,41 +0,0 @@ -// Test bare show without selector. - ---- -#set page(height: 130pt) -#set text(0.7em) - -#align(center)[ - #text(1.3em)[*Essay on typography*] \ - T. Ypst -] - -#show: columns.with(2) -Great typography is at the essence of great storytelling. It is the medium that -transports meaning from parchment to reader, the wave that sparks a flame -in booklovers and the great fulfiller of human need. - ---- -// Test bare show in content block. -A #[_B #show: c => [*#c*]; C_] D - ---- -// Test style precedence. -#set text(fill: eastern, size: 1.5em) -#show: text.with(fill: forest) -Forest - ---- -#show: [Shown] -Ignored - ---- -// Error: 4-19 show is only allowed directly in code and content blocks -#((show: body => 2) * body) - ---- -// Error: 6 expected colon -#show it => {} - ---- -// Error: 6 expected colon -#show it diff --git a/tests/typ/compiler/show-node.typ b/tests/typ/compiler/show-node.typ deleted file mode 100644 index ff2bdb5a..00000000 --- a/tests/typ/compiler/show-node.typ +++ /dev/null @@ -1,104 +0,0 @@ -// Test show rules. - ---- -// Override lists. -#show list: it => "(" + it.children.map(v => v.body).join(", ") + ")" - -- A - - B - - C -- D -- E - ---- -// Test full reset. -#show heading: [B] -#show heading: set text(size: 10pt, weight: 400) -A #[= Heading] C - ---- -// Test full removal. -#show heading: none - -Where is -= There are no headings around here! -my heading? - ---- -// Test integrated example. -#show heading: it => block({ - set text(10pt) - box(move(dy: -1pt)[📖]) - h(5pt) - if it.level == 1 { - underline(text(1.25em, blue, it.body)) - } else { - text(red, it.body) - } -}) - -= Task 1 -Some text. - -== Subtask -Some more text. - -= Task 2 -Another text. - ---- -// Test set and show in code blocks. -#show heading: it => { - set text(red) - show "ding": [🛎] - it.body -} - -= Heading - ---- -// Test that scoping works as expected. -#{ - let world = [ World ] - show "W": strong - world - { - set text(blue) - show: it => { - show "o": "Ø" - it - } - world - } - world -} - ---- -#show heading: [1234] -= Heading - ---- -// Error: 25-29 content does not contain field "page" -#show heading: it => it.page -= Heading - ---- -#show text: none -Hey - ---- -// Error: 7-12 only element functions can be used as selectors -#show upper: it => {} - ---- -// Error: 16-20 expected content or function, found integer -#show heading: 1234 -= Heading - ---- -// Error: 7-10 expected symbol, string, label, function, regex, or selector, found color -#show red: [] - ---- -// Error: 7-25 show is only allowed directly in code and content blocks -#(1 + show heading: none) diff --git a/tests/typ/compiler/show-recursive.typ b/tests/typ/compiler/show-recursive.typ deleted file mode 100644 index 91a295f2..00000000 --- a/tests/typ/compiler/show-recursive.typ +++ /dev/null @@ -1,51 +0,0 @@ -// Test recursive show rules. - ---- -// Test basic identity. -#show heading: it => it -= Heading - ---- -// Test more recipes down the chain. -#show list: scale.with(origin: left, x: 80%) -#show heading: [] -#show enum: [] -- Actual -- Tight -- List -= Nope - ---- -// Test show rule in function. -#let starwars(body) = { - show list: it => block({ - stack(dir: ltr, - text(red, it), - 1fr, - scale(x: -100%, text(blue, it)), - ) - }) - body -} - -- Normal list - -#starwars[ - - Star - - Wars - - List -] - -- Normal list - ---- -// Test multi-recursion with nested lists. -#set rect(inset: 3pt) -#show list: rect.with(stroke: blue) -#show list: rect.with(stroke: red) -#show list: block - -- List - - Nested - - List -- Recursive! diff --git a/tests/typ/compiler/show-selector-logical.typ b/tests/typ/compiler/show-selector-logical.typ deleted file mode 100644 index a11e20b6..00000000 --- a/tests/typ/compiler/show-selector-logical.typ +++ /dev/null @@ -1,21 +0,0 @@ -// Test and/or selectors in show rules. - ---- -// Looking forward to `heading.where(level: 1 | 2)` :) -#show heading.where(level: 1).or(heading.where(level: 2)): set text(red) -= L1 -== L2 -=== L3 -==== L4 - ---- -// Test element selector combined with label selector. -#show selector(strong).or(<special>): highlight -I am *strong*, I am _emphasized_, and I am #[special<special>]. - ---- -// Ensure that text selector cannot be nested in and/or. That's too complicated, -// at least for now. - -// Error: 7-41 this selector cannot be used with show -#show heading.where(level: 1).or("more"): set text(red) diff --git a/tests/typ/compiler/show-selector.typ b/tests/typ/compiler/show-selector.typ deleted file mode 100644 index db6db40f..00000000 --- a/tests/typ/compiler/show-selector.typ +++ /dev/null @@ -1,39 +0,0 @@ -// Test show rule patterns. - ---- -// Inline code. -#show raw.where(block: false): box.with( - radius: 2pt, - outset: (y: 2.5pt), - inset: (x: 3pt, y: 0pt), - fill: luma(230), -) - -// Code blocks. -#show raw.where(block: true): block.with( - outset: -3pt, - inset: 11pt, - fill: luma(230), - stroke: (left: 1.5pt + luma(180)), -) - -#set page(margin: (top: 12pt)) -#set par(justify: true) - -This code tests `code` -with selectors and justification. - -```rs -code!("it"); -``` - -You can use the ```rs *const T``` pointer or -the ```rs &mut T``` reference. - ---- -#show heading: set text(green) -#show heading.where(level: 1): set text(red) -#show heading.where(level: 2): set text(blue) -= Red -== Blue -=== Green diff --git a/tests/typ/compiler/show-set-func.typ b/tests/typ/compiler/show-set-func.typ deleted file mode 100644 index 0447d946..00000000 --- a/tests/typ/compiler/show-set-func.typ +++ /dev/null @@ -1,16 +0,0 @@ -// Test set rules on an element in show rules for said element. - ---- -// These are both red because in the expanded form, `set text(red)` ends up -// closer to the content than `set text(blue)`. -#show strong: it => { set text(red); it } -Hello *World* - -#show strong: it => { set text(blue); it } -Hello *World* - ---- -// This doesn't have an effect. An element is materialized before any show -// rules run. -#show heading: it => { set heading(numbering: "(I)"); it } -= Heading diff --git a/tests/typ/compiler/show-set-text.typ b/tests/typ/compiler/show-set-text.typ deleted file mode 100644 index 464cad90..00000000 --- a/tests/typ/compiler/show-set-text.typ +++ /dev/null @@ -1,41 +0,0 @@ -// Text show-set rules are weird. - ---- -#show "He": set text(red) -#show "ya": set text(blue) -Heya - ---- -#show "Heya": set text(red) -#show "ya": set text(blue) -Heya - ---- -#show "He": set text(red) -#show "Heya": set text(blue) -Heya - ---- -#show "Heya": set text(red) -#show "yaho": set text(blue) -Heyaho - ---- -#show "He": set text(red) -#show "ya": set text(weight: "bold") -Heya - ---- -#show "Heya": set text(red) -#show "ya": set text(weight: "bold") -Heya - ---- -#show "He": set text(red) -#show "Heya": set text(weight: "bold") -Heya - ---- -#show "Heya": set text(red) -#show "yaho": set text(weight: "bold") -Heyaho diff --git a/tests/typ/compiler/show-set.typ b/tests/typ/compiler/show-set.typ deleted file mode 100644 index e336f517..00000000 --- a/tests/typ/compiler/show-set.typ +++ /dev/null @@ -1,55 +0,0 @@ -// Test show-set rules. - ---- -// Test overriding show-set rules. -#show strong: set text(red) -Hello *World* - -#show strong: set text(blue) -Hello *World* - ---- -// Test show-set rule on the same element. -#set figure(supplement: [Default]) -#show figure.where(kind: table): set figure(supplement: [Tableau]) -#figure( - table(columns: 2)[A][B][C][D], - caption: [Four letters], -) - ---- -// Test both things at once. -#show heading: set text(red) -= Level 1 -== Level 2 - -#show heading.where(level: 1): set text(blue) -#show heading.where(level: 1): set text(green) -#show heading.where(level: 1): set heading(numbering: "(I)") -= Level 1 -== Level 2 - ---- -// Test setting the thing we just matched on. -// This is quite cursed, but it works. -#set heading(numbering: "(I)") -#show heading.where(numbering: "(I)"): set heading(numbering: "1.") -= Heading - ---- -// Same thing, but even more cursed, because `kind` is synthesized. -#show figure.where(kind: table): set figure(kind: raw) -#figure(table[A], caption: [Code]) - ---- -// Test that show-set rules on the same element don't affect each other. This -// could be implemented, but isn't as of yet. -#show heading.where(level: 1): set heading(numbering: "(I)") -#show heading.where(numbering: "(I)"): set text(red) -= Heading - ---- -// Test show-set rules on layoutable element to ensure it is realized -// even though it implements `LayoutMultiple`. -#show table: set text(red) -#pad(table(columns: 4)[A][B][C][D]) diff --git a/tests/typ/compiler/show-text.typ b/tests/typ/compiler/show-text.typ deleted file mode 100644 index a42abfb2..00000000 --- a/tests/typ/compiler/show-text.typ +++ /dev/null @@ -1,93 +0,0 @@ -// Test text replacement show rules. - ---- -// Test classic example. -#set text(font: "Roboto") -#show "Der Spiegel": smallcaps -Die Zeitung Der Spiegel existiert. - ---- -// Another classic example. -#show "TeX": [T#h(-0.145em)#box(move(dy: 0.233em)[E])#h(-0.135em)X] -#show regex("(Lua)?(La)?TeX"): name => box(text(font: "New Computer Modern")[#name]) - -TeX, LaTeX, LuaTeX and LuaLaTeX! - ---- -// Test direct cycle. -#show "Hello": text(red)[Hello] -Hello World! - ---- -// Test replacing text with raw text. -#show "rax": `rax` -The register rax. - ---- -// Test indirect cycle. -#show "Good": [Typst!] -#show "Typst": [Fun!] -#show "Fun": [Good!] - -#set text(ligatures: false) -Good \ -Fun \ -Typst \ - ---- -// Test that replacements happen exactly once. -#show "A": [BB] -#show "B": [CC] -AA (8) - ---- -// Test caseless match and word boundaries. -#show regex("(?i)\bworld\b"): [🌍] - -Treeworld, the World of worlds, is a world. - ---- -// Test there is no crashing on empty strings -// Error: 1:7-1:9 text selector is empty -#show "": [] - ---- -// Error: 1:7-1:16 regex selector is empty -#show regex(""): [AA] - ---- -// Error: 1:7-1:42 regex matches empty text -#show regex("(VAR_GLOBAL|END_VAR||BOOL)") : [] - ---- -// This is a fun one. -#set par(justify: true) -#show regex("\S"): letter => box(stroke: 1pt, inset: 2pt, upper(letter)) -#lorem(5) - ---- -// See also: https://github.com/mTvare6/hello-world.rs -#show regex("(?i)rust"): it => [#it (🚀)] -Rust is memory-safe and blazingly fast. Let's rewrite everything in rust. - ---- -// Test accessing the string itself. -#show "hello": it => it.text.split("").map(upper).join("|") -Oh, hello there! - ---- -// Replace worlds but only in lists. -#show list: it => [ - #show "World": [🌎] - #it -] - -World -- World - ---- -// Test absolute path in layout phase. - -#show "GRAPH": image("/assets/images/graph.png") - -The GRAPH has nodes. diff --git a/tests/typ/compiler/spread.typ b/tests/typ/compiler/spread.typ deleted file mode 100644 index db658453..00000000 --- a/tests/typ/compiler/spread.typ +++ /dev/null @@ -1,133 +0,0 @@ -// Test argument sinks and spreading. -// Ref: false - ---- -// Test standard argument overriding. -#{ - let f(style: "normal", weight: "regular") = { - "(style: " + style + ", weight: " + weight + ")" - } - - let myf(..args) = f(weight: "bold", ..args) - test(myf(), "(style: normal, weight: bold)") - test(myf(weight: "black"), "(style: normal, weight: black)") - test(myf(style: "italic"), "(style: italic, weight: bold)") -} - ---- -// Test multiple calls. -#{ - let f(b, c: "!") = b + c - let g(a, ..sink) = a + f(..sink) - test(g("a", "b", c: "c"), "abc") -} - ---- -// Test doing things with arguments. -#{ - let save(..args) = { - test(type(args), arguments) - test(repr(args), "(three: true, 1, 2)") - } - - save(1, 2, three: true) -} - ---- -// Test spreading array and dictionary. -#{ - let more = (3, -3, 6, 10) - test(calc.min(1, 2, ..more), -3) - test(calc.max(..more, 9), 10) - test(calc.max(..more, 11), 11) -} - -#{ - let more = (c: 3, d: 4) - let tostr(..args) = repr(args) - test(tostr(a: 1, ..more, b: 2), "(a: 1, c: 3, d: 4, b: 2)") -} - ---- -// None is spreadable. -#let f() = none -#f(..none) -#f(..if false {}) -#f(..for x in () []) - ---- -// unnamed spread -#let f(.., a) = a -#test(f(1, 2, 3), 3) - ---- -// Error: 11-19 cannot spread string -#calc.min(.."nope") - ---- -// Error: 10-14 expected pattern, found boolean -#let f(..true) = none - ---- -// Error: 13-16 only one argument sink is allowed -#let f(..a, ..b) = none - ---- -// Test spreading into array and dictionary. -#{ - let l = (1, 2, 3) - let r = (5, 6, 7) - test((..l, 4, ..r), range(1, 8)) - test((..none), ()) -} - -#{ - let x = (a: 1) - let y = (b: 2) - let z = (a: 3) - test((:..x, ..y, ..z), (a: 3, b: 2)) - test((..(a: 1), b: 2), (a: 1, b: 2)) -} - ---- -// Error: 9-17 cannot spread dictionary into array -#(1, 2, ..(a: 1)) - ---- -// Error: 3-11 cannot spread array into dictionary -#(..(1, 2), a: 1) - ---- -// Spread at beginning. -#{ - let f(..a, b) = (a, b) - test(repr(f(1)), "((), 1)") - test(repr(f(1, 2, 3)), "((1, 2), 3)") - test(repr(f(1, 2, 3, 4, 5)), "((1, 2, 3, 4), 5)") -} - ---- -// Spread in the middle. -#{ - let f(a, ..b, c) = (a, b, c) - test(repr(f(1, 2)), "(1, (), 2)") - test(repr(f(1, 2, 3, 4, 5)), "(1, (2, 3, 4), 5)") -} - ---- -// Unnamed sink should just ignore any extra arguments. -#{ - let f(a, b: 5, ..) = (a, b) - test(f(4), (4, 5)) - test(f(10, b: 11), (10, 11)) - test(f(13, 20, b: 12), (13, 12)) - test(f(15, b: 16, c: 13), (15, 16)) -} - ---- -#{ - let f(..a, b, c, d) = none - - // Error: 3-10 missing argument: d - f(1, 2) -} diff --git a/tests/typ/compiler/string.typ b/tests/typ/compiler/string.typ deleted file mode 100644 index 949a2154..00000000 --- a/tests/typ/compiler/string.typ +++ /dev/null @@ -1,247 +0,0 @@ -// Test the string methods. -// Ref: false - ---- -// Test the `len` method. -#test("Hello World!".len(), 12) - ---- -// Test the `first` and `last` methods. -#test("Hello".first(), "H") -#test("Hello".last(), "o") -#test("🏳️🌈A🏳️⚧️".first(), "🏳️🌈") -#test("🏳️🌈A🏳️⚧️".last(), "🏳️⚧️") - ---- -// Error: 2-12 string is empty -#"".first() - ---- -// Error: 2-11 string is empty -#"".last() - ---- -// Test the `at` method. -#test("Hello".at(1), "e") -#test("Hello".at(4), "o") -#test("Hello".at(-1), "o") -#test("Hello".at(-2), "l") -#test("Hey: 🏳️🌈 there!".at(5), "🏳️🌈") - ---- -// Test `at`'s 'default' parameter. -#test("z", "Hello".at(5, default: "z")) - ---- -// Error: 2-14 string index 2 is not a character boundary -#"🏳️🌈".at(2) - ---- -// Error: 2-15 no default value was specified and string index out of bounds (index: 5, len: 5) -#"Hello".at(5) - ---- -#test("Hello".at(5, default: (a: 10)), (a: 10)) - ---- -// Test the `slice` method. -#test("abc".slice(1, 2), "b") -#test("abc🏡def".slice(2, 7), "c🏡") -#test("abc🏡def".slice(2, -2), "c🏡d") -#test("abc🏡def".slice(-3, -1), "de") - ---- -// Error: 2-21 string index -1 is not a character boundary -#"🏳️🌈".slice(0, -1) - ---- -// Test the `clusters` and `codepoints` methods. -#test("abc".clusters(), ("a", "b", "c")) -#test("abc".clusters(), ("a", "b", "c")) -#test("🏳️🌈!".clusters(), ("🏳️🌈", "!")) -#test("🏳️🌈!".codepoints(), ("🏳", "\u{fe0f}", "\u{200d}", "🌈", "!")) - ---- -// Test the `contains` method. -#test("abc".contains("b"), true) -#test("b" in "abc", true) -#test("1234f".contains(regex("\d")), true) -#test(regex("\d") in "1234f", true) -#test("abc".contains("d"), false) -#test("1234g" in "1234f", false) -#test("abc".contains(regex("^[abc]$")), false) -#test("abc".contains(regex("^[abc]+$")), true) - ---- -// Test the `starts-with` and `ends-with` methods. -#test("Typst".starts-with("Ty"), true) -#test("Typst".starts-with(regex("[Tt]ys")), false) -#test("Typst".starts-with("st"), false) -#test("Typst".ends-with("st"), true) -#test("Typst".ends-with(regex("\d*")), true) -#test("Typst".ends-with(regex("\d+")), false) -#test("Typ12".ends-with(regex("\d+")), true) -#test("typst13".ends-with(regex("1[0-9]")), true) -#test("typst113".ends-with(regex("1[0-9]")), true) -#test("typst23".ends-with(regex("1[0-9]")), false) - ---- -// Test the `find` and `position` methods. -#let date = regex("\d{2}:\d{2}") -#test("Hello World".find("World"), "World") -#test("Hello World".position("World"), 6) -#test("It's 12:13 now".find(date), "12:13") -#test("It's 12:13 now".position(date), 5) - ---- -// Test the `match` method. -#test("Is there a".match("for this?"), none) -#test( - "The time of my life.".match(regex("[mit]+e")), - (start: 4, end: 8, text: "time", captures: ()), -) - -// Test the `matches` method. -#test("Hello there".matches("\d"), ()) -#test("Day by Day.".matches("Day"), ( - (start: 0, end: 3, text: "Day", captures: ()), - (start: 7, end: 10, text: "Day", captures: ()), -)) - -// Compute the sum of all timestamps in the text. -#let timesum(text) = { - let time = 0 - for match in text.matches(regex("(\d+):(\d+)")) { - let caps = match.captures - time += 60 * int(caps.at(0)) + int(caps.at(1)) - } - str(int(time / 60)) + ":" + str(calc.rem(time, 60)) -} - -#test(timesum(""), "0:0") -#test(timesum("2:70"), "3:10") -#test(timesum("1:20, 2:10, 0:40"), "4:10") - ---- -// Test the `replace` method with `Str` replacements. -#test("ABC".replace("", "-"), "-A-B-C-") -#test("Ok".replace("Ok", "Nope", count: 0), "Ok") -#test("to add?".replace("", "How ", count: 1), "How to add?") -#test("AB C DEF GH J".replace(" ", ",", count: 2), "AB,C,DEF GH J") -#test("Walcemo" - .replace("o", "k") - .replace("e", "o") - .replace("k", "e") - .replace("a", "e"), - "Welcome" -) -#test("123".replace(regex("\d$"), "_"), "12_") -#test("123".replace(regex("\d{1,2}$"), "__"), "1__") - ---- -// Test the `replace` method with `Func` replacements. - -#test("abc".replace(regex("[a-z]"), m => { - str(m.start) + m.text + str(m.end) -}), "0a11b22c3") -#test("abcd, efgh".replace(regex("\w+"), m => { - upper(m.text) -}), "ABCD, EFGH") -#test("hello : world".replace(regex("^(.+)\s*(:)\s*(.+)$"), m => { - upper(m.captures.at(0)) + m.captures.at(1) + " " + upper(m.captures.at(2)) -}), "HELLO : WORLD") -#test("hello world, lorem ipsum".replace(regex("(\w+) (\w+)"), m => { - m.captures.at(1) + " " + m.captures.at(0) -}), "world hello, ipsum lorem") -#test("hello world, lorem ipsum".replace(regex("(\w+) (\w+)"), count: 1, m => { - m.captures.at(1) + " " + m.captures.at(0) -}), "world hello, lorem ipsum") -#test("123 456".replace(regex("[a-z]+"), "a"), "123 456") - -#test("abc".replace("", m => "-"), "-a-b-c-") -#test("abc".replace("", m => "-", count: 1), "-abc") -#test("123".replace("abc", m => ""), "123") -#test("123".replace("abc", m => "", count: 2), "123") -#test("a123b123c".replace("123", m => { - str(m.start) + "-" + str(m.end) -}), "a1-4b5-8c") -#test("halla warld".replace("a", m => { - if m.start == 1 { "e" } - else if m.start == 4 or m.start == 7 { "o" } -}), "hello world") -#test("aaa".replace("a", m => str(m.captures.len())), "000") - ---- -// Error: 23-24 expected string, found integer -#"123".replace("123", m => 1) - ---- -// Error: 23-32 expected string or function, found array -#"123".replace("123", (1, 2, 3)) - ---- -// Test the `trim` method; the pattern is not provided. -#let str = "Typst, LaTeX, Word, InDesign" -#let array = ("Typst", "LaTeX", "Word", "InDesign") -#test(str.split(",").map(s => s.trim()), array) -#test("".trim(), "") -#test(" ".trim(), "") -#test("\t".trim(), "") -#test("\n".trim(), "") -#test("\t \n".trim(), "") -#test(" abc ".trim(at: start), "abc ") -#test("\tabc ".trim(at: start), "abc ") -#test("abc\n".trim(at: end), "abc") -#test(" abc ".trim(at: end, repeat: true), " abc") -#test(" abc".trim(at: start, repeat: false), "abc") - ---- -// Test the `trim` method; the pattern is a string. -#test("aabcaa".trim("a", repeat: false), "abca") -#test("aabca".trim("a", at: start), "bca") -#test("aabcaa".trim("a", at: end, repeat: false), "aabca") -#test(" abc\n".trim("\n"), " abc") -#test("whole".trim("whole", at: start), "") - ---- -// Test the `trim` method; the pattern is a regex. -#test("".trim(regex(".")), "") -#test("123abc456".trim(regex("\d")), "abc") -#test("123abc456".trim(regex("\d"), repeat: false), "23abc45") -#test("123a4b5c678".trim(regex("\d"), repeat: true), "a4b5c") -#test("123a4b5c678".trim(regex("\d"), repeat: false), "23a4b5c67") -#test("123abc456".trim(regex("\d"), at: start), "abc456") -#test("123abc456".trim(regex("\d"), at: end), "123abc") -#test("123abc456".trim(regex("\d+"), at: end, repeat: false), "123abc") -#test("123abc456".trim(regex("\d{1,2}$"), repeat: false), "123abc4") -#test("hello world".trim(regex(".")), "") -#test("12306".trim(regex("\d"), at: start), "") -#test("12306abc".trim(regex("\d"), at: start), "abc") -#test("whole".trim(regex("whole"), at: start), "") -#test("12306".trim(regex("\d"), at: end), "") -#test("abc12306".trim(regex("\d"), at: end), "abc") -#test("whole".trim(regex("whole"), at: end), "") - ---- -// Error: 17-21 expected either `start` or `end` -#"abc".trim(at: left) - ---- -// Test the `split` method. -#test("abc".split(""), ("", "a", "b", "c", "")) -#test("abc".split("b"), ("a", "c")) -#test("a123c".split(regex("\d")), ("a", "", "", "c")) -#test("a123c".split(regex("\d+")), ("a", "c")) - ---- -// Test the `rev` method. -#test("abc".rev(), "cba") -#test("ax̂e".rev(), "ex̂a") - ---- -// Error: 12-15 unknown variable: arg -#"abc".rev(arg) - ---- -// Error: 2-2:1 unclosed string -#"hello\" diff --git a/tests/typ/compiler/type-compatibility.typ b/tests/typ/compiler/type-compatibility.typ deleted file mode 100644 index 664981f4..00000000 --- a/tests/typ/compiler/type-compatibility.typ +++ /dev/null @@ -1,10 +0,0 @@ -// Test compatibility between types and strings. -// Ref: false - ---- -#test(type(10), int) -#test(type(10), "integer") -#test("is " + type(10), "is integer") -#test(int in ("integer", "string"), true) -#test(int in "integers or strings", true) -#test(str in "integers or strings", true) diff --git a/tests/typ/compiler/while.typ b/tests/typ/compiler/while.typ deleted file mode 100644 index 56409c6e..00000000 --- a/tests/typ/compiler/while.typ +++ /dev/null @@ -1,60 +0,0 @@ -// Test while expressions. - ---- -// Should output `2 4 6 8 10`. -#let i = 0 -#while i < 10 [ - #(i += 2) - #i -] - -// Should output `Hi`. -#let iter = true -#while iter { - iter = false - "Hi." -} - -#while false { - dont-care -} - ---- -// Value of while loops. -// Ref: false - -#test(while false {}, none) - -#let i = 0 -#test(type(while i < 1 [#(i += 1)]), content) - ---- -// Condition must be boolean. -// Error: 8-14 expected boolean, found content -#while [nope] [nope] - ---- -// Error: 8-25 condition is always true -#while 2 < "hello".len() {} - ---- -// Error: 2:2-2:24 loop seems to be infinite -#let i = 1 -#while i > 0 { i += 1 } - ---- -// Error: 7 expected expression -#while - -// Error: 8 expected expression -#{while} - -// Error: 9 expected block -#while x - -// Error: 7 expected expression -#while -x {} - -// Error: 9 expected block -#while x something diff --git a/tests/typ/compute/calc.typ b/tests/typ/compute/calc.typ deleted file mode 100644 index 94a13105..00000000 --- a/tests/typ/compute/calc.typ +++ /dev/null @@ -1,355 +0,0 @@ -// Test math functions. -// Ref: false - ---- -// Test conversion to numbers. -#test(int(false), 0) -#test(int(true), 1) -#test(int(10), 10) -#test(int("150"), 150) -#test(int("-834"), -834) -#test(int("\u{2212}79"), -79) -#test(int(10 / 3), 3) -#test(float(10), 10.0) -#test(float(50% * 30%), 0.15) -#test(float("31.4e-1"), 3.14) -#test(float("31.4e\u{2212}1"), 3.14) -#test(float("3.1415"), 3.1415) -#test(float("-7654.321"), -7654.321) -#test(float("\u{2212}7654.321"), -7654.321) -#test(type(float(10)), float) - ---- -// Test float `is-nan()`. -#test(float(calc.nan).is-nan(), true) -#test(float(10).is-nan(), false) - ---- -// Test float `is-infinite()`. -#test(float(calc.inf).is-infinite(), true) -#test(float(-calc.inf).is-infinite(), true) -#test(float(10).is-infinite(), false) -#test(float(-10).is-infinite(), false) - ---- -// Test float `signum()` -#test(float(0.0).signum(), 1.0) -#test(float(1.0).signum(), 1.0) -#test(float(-1.0).signum(), -1.0) -#test(float(10.0).signum(), 1.0) -#test(float(-10.0).signum(), -1.0) -#test(float(calc.nan).signum().is-nan(), true) - ---- -// Test int `signum()` -#test(int(0).signum(), 0) -#test(int(1.0).signum(), 1) -#test(int(-1.0).signum(), -1) -#test(int(10.0).signum(), 1) -#test(int(-10.0).signum(), -1) - ---- -#test(calc.round(calc.e, digits: 2), 2.72) -#test(calc.round(calc.pi, digits: 2), 3.14) - ---- -// Error: 6-10 expected integer, boolean, float, or string, found length -#int(10pt) - ---- -// Error: 8-13 expected float, boolean, integer, ratio, or string, found type -#float(float) - ---- -// Error: 6-12 invalid integer: nope -#int("nope") - ---- -// Error: 8-15 invalid float: 1.2.3 -#float("1.2.3") - ---- -// Test the `abs` function. -#test(calc.abs(-3), 3) -#test(calc.abs(3), 3) -#test(calc.abs(-0.0), 0.0) -#test(calc.abs(0.0), -0.0) -#test(calc.abs(-3.14), 3.14) -#test(calc.abs(50%), 50%) -#test(calc.abs(-25%), 25%) - ---- -// Error: 11-22 expected integer, float, length, angle, ratio, or fraction, found string -#calc.abs("no number") - ---- -// Test the `even` and `odd` functions. -#test(calc.even(2), true) -#test(calc.odd(2), false) -#test(calc.odd(-1), true) -#test(calc.even(-11), false) - ---- -// Test the `rem` function. -#test(calc.rem(1, 1), 0) -#test(calc.rem(5, 3), 2) -#test(calc.rem(5, -3), 2) -#test(calc.rem(22.5, 10), 2.5) -#test(calc.rem(9, 4.5), 0) - ---- -// Error: 14-15 divisor must not be zero -#calc.rem(5, 0) - ---- -// Error: 16-19 divisor must not be zero -#calc.rem(3.0, 0.0) - ---- -// Test the `div-euclid` function. -#test(calc.div-euclid(7, 3), 2) -#test(calc.div-euclid(7, -3), -2) -#test(calc.div-euclid(-7, 3), -3) -#test(calc.div-euclid(-7, -3), 3) -#test(calc.div-euclid(2.5, 2), 1) - ---- -// Error: 21-22 divisor must not be zero -#calc.div-euclid(5, 0) - ---- -// Error: 23-26 divisor must not be zero -#calc.div-euclid(3.0, 0.0) - ---- -// Test the `rem-euclid` function. -#test(calc.rem-euclid(7, 3), 1) -#test(calc.rem-euclid(7, -3), 1) -#test(calc.rem-euclid(-7, 3), 2) -#test(calc.rem-euclid(-7, -3), 2) -#test(calc.rem-euclid(2.5, 2), 0.5) - ---- -// Error: 21-22 divisor must not be zero -#calc.rem-euclid(5, 0) - ---- -// Error: 23-26 divisor must not be zero -#calc.rem-euclid(3.0, 0.0) - ---- -// Test the `quo` function. -#test(calc.quo(1, 1), 1) -#test(calc.quo(5, 3), 1) -#test(calc.quo(5, -3), -1) -#test(calc.quo(22.5, 10), 2) -#test(calc.quo(9, 4.5), 2) - ---- -// Error: 14-15 divisor must not be zero -#calc.quo(5, 0) - ---- -// Error: 16-19 divisor must not be zero -#calc.quo(3.0, 0.0) - ---- -// Test the `min` and `max` functions. -#test(calc.min(2, -4), -4) -#test(calc.min(3.5, 1e2, -0.1, 3), -0.1) -#test(calc.max(-3, 11), 11) -#test(calc.min("hi"), "hi") - ---- -// Test the `pow`, `log`, `exp`, and `ln` functions. -#test(calc.pow(10, 0), 1) -#test(calc.pow(2, 4), 16) -#test(calc.exp(2), calc.pow(calc.e, 2)) -#test(calc.ln(10), calc.log(10, base: calc.e)) - ---- -// Test the `bit-not`, `bit-and`, `bit-or` and `bit-xor` functions. -#test(64.bit-not(), -65) -#test(0.bit-not(), -1) -#test((-56).bit-not(), 55) -#test(128.bit-and(192), 128) -#test(192.bit-and(224), 192) -#test((-1).bit-and(325532), 325532) -#test(0.bit-and(-53), 0) -#test(0.bit-or(-1), -1) -#test(5.bit-or(3), 7) -#test((-50).bit-or(3), -49) -#test(64.bit-or(32), 96) -#test((-1).bit-xor(1), -2) -#test(64.bit-xor(96), 32) -#test((-1).bit-xor(-7), 6) -#test(0.bit-xor(492), 492) - ---- -// Test the `bit-lshift` and `bit-rshift` functions. -#test(32.bit-lshift(2), 128) -#test(694.bit-lshift(0), 694) -#test(128.bit-rshift(2), 32) -#test(128.bit-rshift(12345), 0) -#test((-7).bit-rshift(2), -2) -#test((-7).bit-rshift(12345), -1) -#test(128.bit-rshift(2, logical: true), 32) -#test((-7).bit-rshift(61, logical: true), 7) -#test(128.bit-rshift(12345, logical: true), 0) -#test((-7).bit-rshift(12345, logical: true), 0) - ---- -// Error: 2-18 the result is too large -#1.bit-lshift(64) - ---- -// Error: 15-17 number must be at least zero -#1.bit-lshift(-1) - ---- -// Error: 15-17 number must be at least zero -#1.bit-rshift(-1) - ---- -// Error: 2-16 zero to the power of zero is undefined -#calc.pow(0, 0) - ---- -// Error: 14-31 exponent is too large -#calc.pow(2, 10000000000000000) - ---- -// Error: 2-25 the result is too large -#calc.pow(2, 2147483647) - ---- -// Error: 14-36 exponent may not be infinite, subnormal, or NaN -#calc.pow(2, calc.pow(2.0, 10000.0)) - ---- -// Error: 2-19 the result is not a real number -#calc.pow(-1, 0.5) - ---- -// Error: 12-14 cannot take square root of negative number -#calc.sqrt(-1) - ---- -#test(calc.root(12.0, 1), 12.0) -#test(calc.root(9.0, 2), 3.0) -#test(calc.root(27.0, 3), 3.0) -#test(calc.root(-27.0, 3), -3.0) -// 100^(-1/2) = (100^(1/2))^-1 = 1/sqrt(100) -#test(calc.root(100.0, -2), 0.1) - ---- -// Error: 17-18 cannot take the 0th root of a number -#calc.root(1.0, 0) - ---- -// Error: 24-25 negative numbers do not have a real nth root when n is even -#test(calc.root(-27.0, 4), -3.0) - ---- -// Error: 11-13 value must be strictly positive -#calc.log(-1) - ---- -// Error: 20-21 base may not be zero, NaN, infinite, or subnormal -#calc.log(1, base: 0) - ---- -// Error: 2-24 the result is not a real number -#calc.log(10, base: -1) - ---- -// Test the `fact` function. -#test(calc.fact(0), 1) -#test(calc.fact(5), 120) - ---- -// Error: 2-15 the result is too large -#calc.fact(21) - ---- -// Test the `perm` function. -#test(calc.perm(0, 0), 1) -#test(calc.perm(5, 3), 60) -#test(calc.perm(5, 5), 120) -#test(calc.perm(5, 6), 0) - ---- -// Error: 2-19 the result is too large -#calc.perm(21, 21) - ---- -// Test the `binom` function. -#test(calc.binom(0, 0), 1) -#test(calc.binom(5, 3), 10) -#test(calc.binom(5, 5), 1) -#test(calc.binom(5, 6), 0) -#test(calc.binom(6, 2), 15) - ---- -// Test the `gcd` function. -#test(calc.gcd(112, 77), 7) -#test(calc.gcd(12, 96), 12) -#test(calc.gcd(13, 9), 1) -#test(calc.gcd(13, -9), 1) -#test(calc.gcd(272557, 272557), 272557) -#test(calc.gcd(0, 0), 0) -#test(calc.gcd(7, 0), 7) - ---- -// Test the `lcm` function. -#test(calc.lcm(112, 77), 1232) -#test(calc.lcm(12, 96), 96) -#test(calc.lcm(13, 9), 117) -#test(calc.lcm(13, -9), 117) -#test(calc.lcm(272557, 272557), 272557) -#test(calc.lcm(0, 0), 0) -#test(calc.lcm(8, 0), 0) - ---- -// Error: 2-41 the result is too large -#calc.lcm(15486487489457, 4874879896543) - ---- -// Error: 2-12 expected at least one value -#calc.min() - ---- -// Error: 14-18 cannot compare string and integer -#calc.min(1, "hi") - ---- -// Error: 16-19 cannot compare 1pt with 1em -#calc.max(1em, 1pt) - ---- -// Test the `range` function. -#test(range(4), (0, 1, 2, 3)) -#test(range(1, 4), (1, 2, 3)) -#test(range(-4, 2), (-4, -3, -2, -1, 0, 1)) -#test(range(10, 5), ()) -#test(range(10, step: 3), (0, 3, 6, 9)) -#test(range(1, 4, step: 1), (1, 2, 3)) -#test(range(1, 8, step: 2), (1, 3, 5, 7)) -#test(range(5, 2, step: -1), (5, 4, 3)) -#test(range(10, 0, step: -3), (10, 7, 4, 1)) - ---- -// Error: 2-9 missing argument: end -#range() - ---- -// Error: 11-14 expected integer, found float -#range(1, 2.0) - ---- -// Error: 17-22 expected integer, found string -#range(4, step: "one") - ---- -// Error: 18-19 number must not be zero -#range(10, step: 0) diff --git a/tests/typ/compute/construct.typ b/tests/typ/compute/construct.typ deleted file mode 100644 index e429efc5..00000000 --- a/tests/typ/compute/construct.typ +++ /dev/null @@ -1,316 +0,0 @@ -// Test creation and conversion functions. -// Ref: false - ---- -// Compare both ways. -#test-repr(rgb(0%, 30.2%, 70.2%), rgb("004db3")) - -// Alpha channel. -#test(rgb(255, 0, 0, 50%), rgb("ff000080")) - -// Test color modification methods. -#test(rgb(25, 35, 45).lighten(10%), rgb(48, 57, 66)) -#test(rgb(40, 30, 20).darken(10%), rgb(36, 27, 18)) -#test(rgb("#133337").negate(space: rgb), rgb(236, 204, 200)) -#test(white.lighten(100%), white) - -// Color mixing, in Oklab space by default. -#test(rgb(color.mix(rgb("#ff0000"), rgb("#00ff00"))), rgb("#d0a800")) -#test(rgb(color.mix(rgb("#ff0000"), rgb("#00ff00"), space: oklab)), rgb("#d0a800")) -#test(rgb(color.mix(rgb("#ff0000"), rgb("#00ff00"), space: rgb)), rgb("#808000")) - -#test(rgb(color.mix(red, green, blue)), rgb("#909282")) -#test(rgb(color.mix(red, blue, green)), rgb("#909282")) -#test(rgb(color.mix(blue, red, green)), rgb("#909282")) - -// Mix with weights. -#test(rgb(color.mix((red, 50%), (green, 50%))), rgb("#c0983b")) -#test(rgb(color.mix((red, 0.5), (green, 0.5))), rgb("#c0983b")) -#test(rgb(color.mix((red, 5), (green, 5))), rgb("#c0983b")) -#test(rgb(color.mix((green, 5), (white, 0), (red, 5))), rgb("#c0983b")) -#test(color.mix((rgb("#aaff00"), 25%), (rgb("#aa00ff"), 75%), space: rgb), rgb("#aa40bf")) -#test(color.mix((rgb("#aaff00"), 50%), (rgb("#aa00ff"), 50%), space: rgb), rgb("#aa8080")) -#test(color.mix((rgb("#aaff00"), 75%), (rgb("#aa00ff"), 25%), space: rgb), rgb("#aabf40")) - -// Mix in hue-based space. -#test(rgb(color.mix(red, blue, space: color.hsl)), rgb("#c408ff")) -#test(rgb(color.mix((red, 50%), (blue, 100%), space: color.hsl)), rgb("#5100f8")) -// Error: 6-51 cannot mix more than two colors in a hue-based space -#rgb(color.mix(red, blue, white, space: color.hsl)) - ---- -// Test color conversion method kinds -#test(rgb(rgb(10, 20, 30)).space(), rgb) -#test(color.linear-rgb(rgb(10, 20, 30)).space(), color.linear-rgb) -#test(oklab(rgb(10, 20, 30)).space(), oklab) -#test(oklch(rgb(10, 20, 30)).space(), oklch) -#test(color.hsl(rgb(10, 20, 30)).space(), color.hsl) -#test(color.hsv(rgb(10, 20, 30)).space(), color.hsv) -#test(cmyk(rgb(10, 20, 30)).space(), cmyk) -#test(luma(rgb(10, 20, 30)).space(), luma) - -#test(rgb(color.linear-rgb(10, 20, 30)).space(), rgb) -#test(color.linear-rgb(color.linear-rgb(10, 20, 30)).space(), color.linear-rgb) -#test(oklab(color.linear-rgb(10, 20, 30)).space(), oklab) -#test(oklch(color.linear-rgb(10, 20, 30)).space(), oklch) -#test(color.hsl(color.linear-rgb(10, 20, 30)).space(), color.hsl) -#test(color.hsv(color.linear-rgb(10, 20, 30)).space(), color.hsv) -#test(cmyk(color.linear-rgb(10, 20, 30)).space(), cmyk) -#test(luma(color.linear-rgb(10, 20, 30)).space(), luma) - -#test(rgb(oklab(10%, 20%, 30%)).space(), rgb) -#test(color.linear-rgb(oklab(10%, 20%, 30%)).space(), color.linear-rgb) -#test(oklab(oklab(10%, 20%, 30%)).space(), oklab) -#test(oklch(oklab(10%, 20%, 30%)).space(), oklch) -#test(color.hsl(oklab(10%, 20%, 30%)).space(), color.hsl) -#test(color.hsv(oklab(10%, 20%, 30%)).space(), color.hsv) -#test(cmyk(oklab(10%, 20%, 30%)).space(), cmyk) -#test(luma(oklab(10%, 20%, 30%)).space(), luma) - -#test(rgb(oklch(60%, 40%, 0deg)).space(), rgb) -#test(color.linear-rgb(oklch(60%, 40%, 0deg)).space(), color.linear-rgb) -#test(oklab(oklch(60%, 40%, 0deg)).space(), oklab) -#test(oklch(oklch(60%, 40%, 0deg)).space(), oklch) -#test(color.hsl(oklch(60%, 40%, 0deg)).space(), color.hsl) -#test(color.hsv(oklch(60%, 40%, 0deg)).space(), color.hsv) -#test(cmyk(oklch(60%, 40%, 0deg)).space(), cmyk) -#test(luma(oklch(60%, 40%, 0deg)).space(), luma) - -#test(rgb(color.hsl(10deg, 20%, 30%)).space(), rgb) -#test(color.linear-rgb(color.hsl(10deg, 20%, 30%)).space(), color.linear-rgb) -#test(oklab(color.hsl(10deg, 20%, 30%)).space(), oklab) -#test(oklch(color.hsl(10deg, 20%, 30%)).space(), oklch) -#test(color.hsl(color.hsl(10deg, 20%, 30%)).space(), color.hsl) -#test(color.hsv(color.hsl(10deg, 20%, 30%)).space(), color.hsv) -#test(cmyk(color.hsl(10deg, 20%, 30%)).space(), cmyk) -#test(luma(color.hsl(10deg, 20%, 30%)).space(), luma) - -#test(rgb(color.hsv(10deg, 20%, 30%)).space(), rgb) -#test(color.linear-rgb(color.hsv(10deg, 20%, 30%)).space(), color.linear-rgb) -#test(oklab(color.hsv(10deg, 20%, 30%)).space(), oklab) -#test(oklch(color.hsv(10deg, 20%, 30%)).space(), oklch) -#test(color.hsl(color.hsv(10deg, 20%, 30%)).space(), color.hsl) -#test(color.hsv(color.hsv(10deg, 20%, 30%)).space(), color.hsv) -#test(cmyk(color.hsv(10deg, 20%, 30%)).space(), cmyk) -#test(luma(color.hsv(10deg, 20%, 30%)).space(), luma) - -#test(rgb(cmyk(10%, 20%, 30%, 40%)).space(), rgb) -#test(color.linear-rgb(cmyk(10%, 20%, 30%, 40%)).space(), color.linear-rgb) -#test(oklab(cmyk(10%, 20%, 30%, 40%)).space(), oklab) -#test(oklch(cmyk(10%, 20%, 30%, 40%)).space(), oklch) -#test(color.hsl(cmyk(10%, 20%, 30%, 40%)).space(), color.hsl) -#test(color.hsv(cmyk(10%, 20%, 30%, 40%)).space(), color.hsv) -#test(cmyk(cmyk(10%, 20%, 30%, 40%)).space(), cmyk) -#test(luma(cmyk(10%, 20%, 30%, 40%)).space(), luma) - -#test(rgb(luma(10%)).space(), rgb) -#test(color.linear-rgb(luma(10%)).space(), color.linear-rgb) -#test(oklab(luma(10%)).space(), oklab) -#test(oklch(luma(10%)).space(), oklch) -#test(color.hsl(luma(10%)).space(), color.hsl) -#test(color.hsv(luma(10%)).space(), color.hsv) -#test(cmyk(luma(10%)).space(), cmyk) -#test(luma(luma(10%)).space(), luma) - ---- -// Test gray color conversion. -// Ref: true -#stack(dir: ltr, rect(fill: luma(0)), rect(fill: luma(80%))) - ---- -// Error for values that are out of range. -// Error: 11-14 number must be between 0 and 255 -#test(rgb(-30, 15, 50)) - ---- -// Error: 6-11 color string contains non-hexadecimal letters -#rgb("lol") - ---- -// Error: 2-7 missing argument: red component -#rgb() - ---- -// Error: 2-11 missing argument: blue component -#rgb(0, 1) - ---- -// Error: 21-26 expected integer or ratio, found boolean -#rgb(10%, 20%, 30%, false) - ---- -// Error: 10-20 unexpected argument: key -#luma(1, key: "val") - ---- -// Error: 12-24 expected float or ratio, found string -// Error: 26-39 expected float or ratio, found string -#color.mix((red, "yes"), (green, "no"), (green, 10%)) - ---- -// Error: 12-23 expected a color or color-weight pair -#color.mix((red, 1, 2)) - ---- -// Error: 31-38 expected `rgb`, `luma`, `cmyk`, `oklab`, `oklch`, `color.linear-rgb`, `color.hsl`, or `color.hsv`, found string -#color.mix(red, green, space: "cyber") - ---- -// Error: 31-36 expected `rgb`, `luma`, `cmyk`, `oklab`, `oklch`, `color.linear-rgb`, `color.hsl`, or `color.hsv` -#color.mix(red, green, space: image) - ---- -// Error: 31-41 expected `rgb`, `luma`, `cmyk`, `oklab`, `oklch`, `color.linear-rgb`, `color.hsl`, or `color.hsv` -#color.mix(red, green, space: calc.round) - ---- -// Ref: true -#let envelope = symbol( - "🖂", - ("stamped", "🖃"), - ("stamped.pen", "🖆"), - ("lightning", "🖄"), - ("fly", "🖅"), -) - -#envelope -#envelope.stamped -#envelope.pen -#envelope.stamped.pen -#envelope.lightning -#envelope.fly - ---- -// Error: 2-10 expected at least one variant -#symbol() - ---- -// Test conversion to string. -#test(str(123), "123") -#test(str(123, base: 3), "11120") -#test(str(-123, base: 16), "−7b") -#test(str(9223372036854775807, base: 36), "1y2p0ij32e8e7") -#test(str(50.14), "50.14") -#test(str(10 / 3).len() > 10, true) - ---- -// Error: 6-8 expected integer, float, version, bytes, label, type, or string, found content -#str([]) - ---- -// Error: 17-19 base must be between 2 and 36 -#str(123, base: 99) - ---- -// Error: 18-19 base is only supported for integers -#str(1.23, base: 2) - ---- -// Test the unicode function. -#test(str.from-unicode(97), "a") -#test(str.to-unicode("a"), 97) - ---- -// Error: 19-22 expected integer, found content -#str.from-unicode([a]) - ---- -// Error: 17-21 expected exactly one character -#str.to-unicode("ab") - ---- -// Error: 19-21 number must be at least zero -#str.from-unicode(-1) - ---- -// Error: 2-28 0x110000 is not a valid codepoint -#str.from-unicode(0x110000) // 0x10ffff is the highest valid code point - ---- -#assert(range(2, 5) == (2, 3, 4)) - ---- -// Test displaying of dates. -#test(datetime(year: 2023, month: 4, day: 29).display(), "2023-04-29") -#test(datetime(year: 2023, month: 4, day: 29).display("[year]"), "2023") -#test( - datetime(year: 2023, month: 4, day: 29) - .display("[year repr:last_two]"), - "23", -) -#test( - datetime(year: 2023, month: 4, day: 29) - .display("[year] [month repr:long] [day] [week_number] [weekday]"), - "2023 April 29 17 Saturday", -) - -// Test displaying of times -#test(datetime(hour: 14, minute: 26, second: 50).display(), "14:26:50") -#test(datetime(hour: 14, minute: 26, second: 50).display("[hour]"), "14") -#test( - datetime(hour: 14, minute: 26, second: 50) - .display("[hour repr:12 padding:none]"), - "2", -) -#test( - datetime(hour: 14, minute: 26, second: 50) - .display("[hour], [minute], [second]"), "14, 26, 50", -) - -// Test displaying of datetimes -#test( - datetime(year: 2023, month: 4, day: 29, hour: 14, minute: 26, second: 50).display(), - "2023-04-29 14:26:50", -) - -// Test getting the year/month/day etc. of a datetime -#let d = datetime(year: 2023, month: 4, day: 29, hour: 14, minute: 26, second: 50) -#test(d.year(), 2023) -#test(d.month(), 4) -#test(d.weekday(), 6) -#test(d.day(), 29) -#test(d.hour(), 14) -#test(d.minute(), 26) -#test(d.second(), 50) - -#let e = datetime(year: 2023, month: 4, day: 29) -#test(e.hour(), none) -#test(e.minute(), none) -#test(e.second(), none) - -// Test today -#test(datetime.today().display(), "1970-01-01") -#test(datetime.today(offset: auto).display(), "1970-01-01") -#test(datetime.today(offset: 2).display(), "1970-01-01") - ---- -// Error: 2-12 at least one of date or time must be fully specified -#datetime() - ---- -// Error: 2-42 time is invalid -#datetime(hour: 25, minute: 0, second: 0) - ---- -// Error: 2-41 date is invalid -#datetime(year: 2000, month: 2, day: 30) - ---- -// Error: 27-34 missing closing bracket for bracket at index 0 -#datetime.today().display("[year") - ---- -// Error: 27-38 invalid component name 'nothing' at index 1 -#datetime.today().display("[nothing]") - ---- -// Error: 27-50 invalid modifier 'wrong' at index 6 -#datetime.today().display("[year wrong:last_two]") - ---- -// Error: 27-33 expected component name at index 2 -#datetime.today().display(" []") - ---- -// Error: 2-36 failed to format datetime (insufficient information) -#datetime.today().display("[hour]") diff --git a/tests/typ/compute/data.typ b/tests/typ/compute/data.typ deleted file mode 100644 index 03b17aed..00000000 --- a/tests/typ/compute/data.typ +++ /dev/null @@ -1,144 +0,0 @@ -// Test reading structured data and files. -// Ref: false - ---- -// Test reading plain text files -#let data = read("/assets/text/hello.txt") -#test(data, "Hello, world!\n") - ---- -// Error: 18-44 file not found (searched at assets/text/missing.txt) -#let data = read("/assets/text/missing.txt") - ---- -// Error: 18-40 file is not valid utf-8 -#let data = read("/assets/text/bad.txt") - ---- -// Test reading CSV data. -// Ref: true -#set page(width: auto) -#let data = csv("/assets/data/zoo.csv") -#let cells = data.at(0).map(strong) + data.slice(1).flatten() -#table(columns: data.at(0).len(), ..cells) - ---- -// Test reading CSV data with dictionary rows enabled. -#let data = csv("/assets/data/zoo.csv", row-type: dictionary) -#test(data.len(), 3) -#test(data.at(0).Name, "Debby") -#test(data.at(2).Weight, "150kg") -#test(data.at(1).Species, "Tiger") - ---- -// Error: 6-16 file not found (searched at typ/compute/nope.csv) -#csv("nope.csv") - ---- -// Error: 6-28 failed to parse CSV (found 3 instead of 2 fields in line 3) -#csv("/assets/data/bad.csv") - ---- -// Test error numbering with dictionary rows. -// Error: 6-28 failed to parse CSV (found 3 instead of 2 fields in line 3) -#csv("/assets/data/bad.csv", row-type: dictionary) - ---- -// Test reading JSON data. -#let data = json("/assets/data/zoo.json") -#test(data.len(), 3) -#test(data.at(0).name, "Debby") -#test(data.at(2).weight, 150) - ---- -// Error: 7-30 failed to parse JSON (expected value at line 3 column 14) -#json("/assets/data/bad.json") - ---- -// Test reading TOML data. -#let data = toml("/assets/data/toml-types.toml") -#test(data.string, "wonderful") -#test(data.integer, 42) -#test(data.float, 3.14) -#test(data.boolean, true) -#test(data.array, (1, "string", 3.0, false)) -#test(data.inline_table, ("first": "amazing", "second": "greater") ) -#test(data.table.element, 5) -#test(data.table.others, (false, "indeed", 7)) -#test(data.date_time, datetime( - year: 2023, - month: 2, - day: 1, - hour: 15, - minute: 38, - second: 57, -)) -#test(data.date_time2, datetime( - year: 2023, - month: 2, - day: 1, - hour: 15, - minute: 38, - second: 57, -)) -#test(data.date, datetime( - year: 2023, - month: 2, - day: 1, -)) -#test(data.time, datetime( - hour: 15, - minute: 38, - second: 57, -)) - ---- -// Error: 7-30 failed to parse TOML (expected `.`, `=` at line 1 column 16) -#toml("/assets/data/bad.toml") - ---- -// Test reading YAML data -#let data = yaml("/assets/data/yaml-types.yaml") -#test(data.len(), 9) -#test(data.null_key, (none, none)) -#test(data.string, "text") -#test(data.integer, 5) -#test(data.float, 1.12) -#test(data.mapping, ("1": "one", "2": "two")) -#test(data.seq, (1,2,3,4)) -#test(data.bool, false) -#test(data.keys().contains("true"), true) -#test(data.at("1"), "ok") - ---- -// Error: 7-30 failed to parse YAML (did not find expected ',' or ']' at line 2 column 1, while parsing a flow sequence at line 1 column 18) -#yaml("/assets/data/bad.yaml") - ---- -// Test reading XML data. -#let data = xml("/assets/data/hello.xml") -#test(data, (( - tag: "data", - attrs: (:), - children: ( - "\n ", - (tag: "hello", attrs: (name: "hi"), children: ("1",)), - "\n ", - ( - tag: "data", - attrs: (:), - children: ( - "\n ", - (tag: "hello", attrs: (:), children: ("World",)), - "\n ", - (tag: "hello", attrs: (:), children: ("World",)), - "\n ", - ), - ), - "\n", - ), -),)) - ---- -// Error: 6-28 failed to parse XML (found closing tag 'data' instead of 'hello' in line 3) -#xml("/assets/data/bad.xml") diff --git a/tests/typ/compute/eval-path.typ b/tests/typ/compute/eval-path.typ deleted file mode 100644 index 863b6203..00000000 --- a/tests/typ/compute/eval-path.typ +++ /dev/null @@ -1,18 +0,0 @@ -// Test file loading in eval. - ---- -// Test absolute path. -#eval("image(\"/assets/images/tiger.jpg\", width: 50%)") - ---- -#show raw: it => eval(it.text, mode: "markup") - -``` -#show emph: image("/assets/images/tiger.jpg", width: 50%) -_Tiger!_ -``` - ---- -// Test relative path. -// Ref: false -#test(eval(`"HELLO" in read("./eval-path.typ")`.text), true) diff --git a/tests/typ/compute/foundations.typ b/tests/typ/compute/foundations.typ deleted file mode 100644 index eb50c072..00000000 --- a/tests/typ/compute/foundations.typ +++ /dev/null @@ -1,107 +0,0 @@ -// Test foundational functions. -// Ref: false - ---- -#test(type(1), int) -#test(type(ltr), direction) -#test(type(10 / 3), float) - ---- -#test(repr(ltr), "ltr") -#test(repr((1, 2, false, )), "(1, 2, false)") - ---- -// Test panic. -// Error: 2-9 panicked -#panic() - ---- -// Test panic. -// Error: 2-12 panicked with: 123 -#panic(123) - ---- -// Test panic. -// Error: 2-24 panicked with: "this is wrong" -#panic("this is wrong") - ---- -// Test failing assertions. -// Error: 2-16 assertion failed -#assert(1 == 2) - ---- -// Test failing assertions. -// Error: 2-51 assertion failed: two is smaller than one -#assert(2 < 1, message: "two is smaller than one") - ---- -// Test failing assertions. -// Error: 9-15 expected boolean, found string -#assert("true") - ---- -// Test failing assertions. -// Error: 2-19 equality assertion failed: value 10 was not equal to 11 -#assert.eq(10, 11) - ---- -// Test failing assertions. -// Error: 2-55 equality assertion failed: 10 and 12 are not equal -#assert.eq(10, 12, message: "10 and 12 are not equal") - ---- -// Test failing assertions. -// Error: 2-19 inequality assertion failed: value 11 was equal to 11 -#assert.ne(11, 11) - ---- -// Test failing assertions. -// Error: 2-57 inequality assertion failed: must be different from 11 -#assert.ne(11, 11, message: "must be different from 11") - ---- -// Test successful assertions. -#assert(5 > 3) -#assert.eq(15, 15) -#assert.ne(10, 12) - ---- -// Test the `type` function. -#test(type(1), int) -#test(type(ltr), direction) -#test(type(10 / 3), float) - ---- -// Test the eval function. -#test(eval("1 + 2"), 3) -#test(eval("1 + x", scope: (x: 3)), 4) -#test(eval("let x = x + 1; x + 1", scope: (x: 1)), 3) - ---- -// Test evaluation in other modes. -// Ref: true -#eval("[_Hello" + " World!_]") \ -#eval("_Hello" + " World!_", mode: "markup") \ -#eval("RR_1^NN", mode: "math", scope: (RR: math.NN, NN: math.RR)) - ---- -// Error: 7-12 expected pattern -#eval("let") - ---- -#show raw: it => text(font: "PT Sans", eval("[" + it.text + "]")) - -Interacting -``` -#set text(blue) -Blue #move(dy: -0.15em)[🌊] -``` - ---- -// Error: 7-17 cannot continue outside of loop -#eval("continue") - ---- -// Error: 7-12 expected semicolon or line break -#eval("1 2") diff --git a/tests/typ/compute/version.typ b/tests/typ/compute/version.typ deleted file mode 100644 index e33eeb6f..00000000 --- a/tests/typ/compute/version.typ +++ /dev/null @@ -1,47 +0,0 @@ -// Test versions. -// Ref: false - ---- -// Test version constructor. - -// Empty. -#version() - -// Plain. -#version(1, 2) - -// Single Array argument. -#version((1, 2)) - -// Mixed arguments. -#version(1, (2, 3), 4, (5, 6), 7) - ---- -// Test equality of different-length versions -#test(version(), version(0)) -#test(version(0), version(0, 0)) -#test(version(1, 2), version(1, 2, 0, 0, 0, 0)) ---- -// Test `version.at`. - -// Non-negative index in bounds -#test(version(1, 2).at(1), 2) - -// Non-negative index out of bounds -#test(version(1, 2).at(4), 0) - -// Negative index in bounds -#test(version(1, 2).at(-2), 1) - -// Error: 2-22 component index out of bounds (index: -3, len: 2) -#version(1, 2).at(-3) - ---- -// Test version fields. -#test(version(1, 2, 3).major, 1) -#test(version(1, 2, 3).minor, 2) -#test(version(1, 2, 3).patch, 3) - ---- -// Test the type of `sys.version` -#test(type(sys.version), version) diff --git a/tests/typ/layout/align.typ b/tests/typ/layout/align.typ deleted file mode 100644 index 98ee8da5..00000000 --- a/tests/typ/layout/align.typ +++ /dev/null @@ -1,52 +0,0 @@ -// Test alignment. - ---- -#set page(height: 100pt) -#stack(dir: ltr, - align(left, square(size: 15pt, fill: eastern)), - align(center, square(size: 20pt, fill: eastern)), - align(right, square(size: 15pt, fill: eastern)), -) -#align(center + horizon, rect(fill: eastern, height: 10pt)) -#align(bottom, stack( - align(center, rect(fill: conifer, height: 10pt)), - rect(fill: forest, height: 10pt, width: 100%), -)) - ---- -// Test that multiple paragraphs in subflow also respect alignment. -#align(center)[ - Lorem Ipsum - - Dolor -] - ---- -// Test start and end alignment. -#rotate(-30deg, origin: end + horizon)[Hello] - -#set text(lang: "de") -#align(start)[Start] -#align(end)[Ende] - -#set text(lang: "ar") -#align(start)[يبدأ] -#align(end)[نهاية] - ---- -// Ref: false -#test(type(center), alignment) -#test(type(horizon), alignment) -#test(type(center + horizon), alignment) - ---- -// Error: 8-22 cannot add two horizontal alignments -#align(center + right, [A]) - ---- -// Error: 8-20 cannot add two vertical alignments -#align(top + bottom, [A]) - ---- -// Error: 8-30 cannot add a vertical and a 2D alignment -#align(top + (bottom + right), [A]) diff --git a/tests/typ/layout/block-sizing.typ b/tests/typ/layout/block-sizing.typ deleted file mode 100644 index 181bbe31..00000000 --- a/tests/typ/layout/block-sizing.typ +++ /dev/null @@ -1,24 +0,0 @@ -// Test blocks with fixed height. - ---- -#set page(height: 100pt) -#set align(center) - -#lorem(10) -#block(width: 80%, height: 60pt, fill: aqua) -#lorem(6) -#block( - breakable: false, - width: 100%, - inset: 4pt, - fill: aqua, - lorem(8) + colbreak(), -) - ---- -// Layout inside a block with certain dimensions should provide those dimensions. - -#set page(height: 120pt) -#block(width: 60pt, height: 80pt, layout(size => [ - This block has a width of #size.width and height of #size.height -])) diff --git a/tests/typ/layout/block-spacing.typ b/tests/typ/layout/block-spacing.typ deleted file mode 100644 index 2c636676..00000000 --- a/tests/typ/layout/block-spacing.typ +++ /dev/null @@ -1,9 +0,0 @@ -// Test block spacing. - ---- -#set block(spacing: 10pt) -Hello - -There - -#block(spacing: 20pt)[Further down] diff --git a/tests/typ/layout/cjk-latin-spacing.typ b/tests/typ/layout/cjk-latin-spacing.typ deleted file mode 100644 index c6fff5d7..00000000 --- a/tests/typ/layout/cjk-latin-spacing.typ +++ /dev/null @@ -1,29 +0,0 @@ -// Test CJK-Latin spacing. - -#set page(width: 50pt + 10pt, margin: (x: 5pt)) -#set text(lang: "zh", font: "Noto Serif CJK SC", cjk-latin-spacing: auto) -#set par(justify: true) - -中文,中12文1中,文12中文 - -中文,中ab文a中,文ab中文 - -#set text(cjk-latin-spacing: none) - -中文,中12文1中,文12中文 - -中文,中ab文a中,文ab中文 - ---- -// Issue #2538 -#set text(cjk-latin-spacing: auto) - -abc字 - -abc字#linebreak() - -abc字#linebreak() -母 - -abc字\ -母 diff --git a/tests/typ/layout/cjk-punctuation-adjustment.typ b/tests/typ/layout/cjk-punctuation-adjustment.typ deleted file mode 100644 index 88ee9560..00000000 --- a/tests/typ/layout/cjk-punctuation-adjustment.typ +++ /dev/null @@ -1,44 +0,0 @@ -#set page(width: 15em) - -// In the following example, the space between 》! and ? should be squeezed. -// because zh-CN follows GB style -#set text(lang: "zh", region: "CN", font: "Noto Serif CJK SC") -原来,你也玩《原神》!? - -// However, in the following example, the space between 》! and ? should not be squeezed. -// because zh-TW does not follow GB style -#set text(lang: "zh", region: "TW", font: "Noto Serif CJK TC") -原來,你也玩《原神》! ? - -#set text(lang: "zh", region: "CN", font: "Noto Serif CJK SC") -「真的吗?」 - -#set text(lang: "ja", font: "Noto Serif CJK JP") -「本当に?」 ---- - -#set text(lang: "zh", region: "CN", font: "Noto Serif CJK SC") -《书名〈章节〉》 // the space between 〉 and 》 should be squeezed - -〔茸毛〕:很细的毛 // the space between 〕 and : should be squeezed - ---- -#set page(width: 21em) -#set text(lang: "zh", region: "CN", font: "Noto Serif CJK SC") - -// These examples contain extensive use of Chinese punctuation marks, -// from 《Which parentheses should be used when applying parentheses?》. -// link: https://archive.md/2bb1N - - -(〔中〕医、〔中〕药、技)系列评审 - -(长三角[长江三角洲])(GB/T 16159—2012《汉语拼音正词法基本规则》) - -【爱因斯坦(Albert Einstein)】物理学家 - -〔(2009)民申字第1622号〕 - -“江南海北长相忆,浅水深山独掩扉。”([唐]刘长卿《会赦后酬主簿所问》) - -参看1378页〖象形文字〗。(《现代汉语词典》修订本) diff --git a/tests/typ/layout/clip.typ b/tests/typ/layout/clip.typ deleted file mode 100644 index 3ca74556..00000000 --- a/tests/typ/layout/clip.typ +++ /dev/null @@ -1,68 +0,0 @@ -// Test clipping with the `box` and `block` containers. - ---- -// Test box clipping with a rectangle -Hello #box(width: 1em, height: 1em, clip: false)[#rect(width: 3em, height: 3em, fill: red)] -world 1 - -Space - -Hello #box(width: 1em, height: 1em, clip: true)[#rect(width: 3em, height: 3em, fill: red)] -world 2 - ---- -// Test cliping text -#block(width: 5em, height: 2em, clip: false, stroke: 1pt + black)[ - But, soft! what light through -] - -#v(2em) - -#block(width: 5em, height: 2em, clip: true, stroke: 1pt + black)[ - But, soft! what light through yonder window breaks? It is the east, and Juliet - is the sun. -] - ---- -// Test clipping svg glyphs -Emoji: #box(height: 0.5em, stroke: 1pt + black)[🐪, 🌋, 🏞] - -Emoji: #box(height: 0.5em, clip: true, stroke: 1pt + black)[🐪, 🌋, 🏞] - ---- -// Test block clipping over multiple pages. - -#set page(height: 60pt) - -First! - -#block(height: 4em, clip: true, stroke: 1pt + black)[ - But, soft! what light through yonder window breaks? It is the east, and Juliet - is the sun. -] - ---- -// Test clipping with `radius`. - -#set page(height: 60pt) - -#box( - radius: 5pt, - stroke: 2pt + black, - width: 20pt, - height: 20pt, - clip: true, - image("/assets/images/rhino.png", width: 30pt) -) ---- -// Test clipping with `radius`, but without `stroke`. - -#set page(height: 60pt) - -#box( - radius: 5pt, - width: 20pt, - height: 20pt, - clip: true, - image("/assets/images/rhino.png", width: 30pt) -) diff --git a/tests/typ/layout/code-indent-shrink.typ b/tests/typ/layout/code-indent-shrink.typ deleted file mode 100644 index 1527e061..00000000 --- a/tests/typ/layout/code-indent-shrink.typ +++ /dev/null @@ -1,28 +0,0 @@ -// Spaces in raw blocks should not be shrunk -// as it would mess up the indentation of code -// https://github.com/typst/typst/issues/3191 - ---- -#set par(justify: true) - -#show raw.where(block: true): block.with( - fill: luma(240), - inset: 10pt, -) - -#block( - width: 60%, - ```py - for x in xs: - print("x=",x) - ``` -) - ---- -// In normal paragraphs, spaces should still be shrunk. -// The first line here serves as a reference, while the second -// uses non-breaking spaces to create an overflowing line -// (which should shrink). -~~~~No shrinking here - -~~~~The~spaces~on~this~line~shrink
\ No newline at end of file diff --git a/tests/typ/layout/columns.typ b/tests/typ/layout/columns.typ deleted file mode 100644 index ecf636e7..00000000 --- a/tests/typ/layout/columns.typ +++ /dev/null @@ -1,112 +0,0 @@ -// Test the column layouter. - ---- -// Test normal operation and RTL directions. -#set page(height: 3.25cm, width: 7.05cm, columns: 2) -#set text(lang: "ar", font: ("Noto Sans Arabic", "Linux Libertine")) -#set columns(gutter: 30pt) - -#box(fill: conifer, height: 8pt, width: 6pt) وتحفيز -العديد من التفاعلات الكيميائية. (DNA) من أهم الأحماض النووية التي تُشكِّل -إلى جانب كل من البروتينات والليبيدات والسكريات المتعددة -#box(fill: eastern, height: 8pt, width: 6pt) -الجزيئات الضخمة الأربعة الضرورية للحياة. - ---- -// Test the `columns` function. -#set page(width: auto) - -#rect(width: 180pt, height: 100pt, inset: 8pt, columns(2, [ - A special plight has befallen our document. - Columns in text boxes reigned down unto the soil - to waste a year's crop of rich layouts. - The columns at least were graciously balanced. -])) - ---- -// Test columns for a sized page. -#set page(height: 5cm, width: 7.05cm, columns: 2) - -Lorem ipsum dolor sit amet is a common blind text -and I again am in need of filling up this page -#align(bottom, rect(fill: eastern, width: 100%, height: 12pt)) -#colbreak() - -so I'm returning to this trusty tool of tangible terror. -Sure, it is not the most creative way of filling up -a page for a test but it does get the job done. - ---- -// Test the expansion behaviour. -#set page(height: 2.5cm, width: 7.05cm) - -#rect(inset: 6pt, columns(2, [ - ABC \ - BCD - #colbreak() - DEF -])) - ---- -// Test setting a column gutter and more than two columns. -#set page(height: 3.25cm, width: 7.05cm, columns: 3) -#set columns(gutter: 30pt) - -#rect(width: 100%, height: 2.5cm, fill: conifer) #parbreak() -#rect(width: 100%, height: 2cm, fill: eastern) #parbreak() -#circle(fill: eastern) - ---- -// Test the `colbreak` and `pagebreak` functions. -#set page(height: 1cm, width: 7.05cm, columns: 2) - -A -#colbreak() -#colbreak() -B -#pagebreak() -C -#colbreak() -D - ---- -// Test an empty second column. -#set page(width: 7.05cm, columns: 2) - -#rect(width: 100%, inset: 3pt)[So there isn't anything in the second column?] - ---- -// Test columns when one of them is empty. -#set page(width: auto, columns: 3) - -Arbitrary horizontal growth. - ---- -// Test columns in an infinitely high frame. -#set page(width: 7.05cm, columns: 2) - -There can be as much content as you want in the left column -and the document will grow with it. - -#rect(fill: conifer, width: 100%, height: 30pt) - -Only an explicit #colbreak() `#colbreak()` can put content in the -second column. - ---- -// Test a page with a single column. -#set page(height: auto, width: 7.05cm, columns: 1) - -This is a normal page. Very normal. - ---- -// Test a page with zero columns. -// Error: 49-50 number must be positive -#set page(height: auto, width: 7.05cm, columns: 0) - ---- -// Test colbreak after only out-of-flow elements. -#set page(width: 7.05cm, columns: 2) -#place[OOF] -#colbreak() -In flow. diff --git a/tests/typ/layout/container-fill.typ b/tests/typ/layout/container-fill.typ deleted file mode 100644 index f5947e06..00000000 --- a/tests/typ/layout/container-fill.typ +++ /dev/null @@ -1,7 +0,0 @@ -#set page(height: 100pt) -#let words = lorem(18).split() -#block(inset: 8pt, width: 100%, fill: aqua, stroke: aqua.darken(30%))[ - #words.slice(0, 13).join(" ") - #box(fill: teal, outset: 2pt)[tempor] - #words.slice(13).join(" ") -] diff --git a/tests/typ/layout/container.typ b/tests/typ/layout/container.typ deleted file mode 100644 index 8d4ec34b..00000000 --- a/tests/typ/layout/container.typ +++ /dev/null @@ -1,50 +0,0 @@ -// Test the `box` and `block` containers. - ---- -// Test box in paragraph. -A #box[B \ C] D. - -// Test box with height. -Spaced \ -#box(height: 0.5cm) \ -Apart - ---- -// Test block sizing. -#set page(height: 120pt) -#set block(spacing: 0pt) -#block(width: 90pt, height: 80pt, fill: red)[ - #block(width: 60%, height: 60%, fill: green) - #block(width: 50%, height: 60%, fill: blue) -] - ---- -// Test box sizing with layoutable child. -#box( - width: 50pt, - height: 50pt, - fill: yellow, - path( - fill: purple, - (0pt, 0pt), - (30pt, 30pt), - (0pt, 30pt), - (30pt, 0pt), - ), -) - ---- -// Test fr box. -Hello #box(width: 1fr, rect(height: 0.7em, width: 100%)) World - ---- -// Test block over multiple pages. - -#set page(height: 60pt) - -First! - -#block[ - But, soft! what light through yonder window breaks? It is the east, and Juliet - is the sun. -] diff --git a/tests/typ/layout/enum-align.typ b/tests/typ/layout/enum-align.typ deleted file mode 100644 index d64ee374..00000000 --- a/tests/typ/layout/enum-align.typ +++ /dev/null @@ -1,51 +0,0 @@ -// Test the alignment of enum numbers. - ---- -// Alignment shouldn't affect number -#set align(horizon) - -+ ABCDEF\ GHIJKL\ MNOPQR - + INNER\ INNER\ INNER -+ BACK\ HERE - ---- -// Enum number alignment should be 'end' by default -1. a -10. b -100. c - -#set enum(number-align: start) -1. a -8. b -16. c - ---- -#set enum(number-align: center + horizon) -1. #box(fill: teal, inset: 10pt )[a] -8. #box(fill: teal, inset: 10pt )[b] -16. #box(fill: teal,inset: 10pt )[c] - ---- -// Number align option should not be affected by the context. -#set align(center) -#set enum(number-align: start) - -4. c -8. d -16. e\ f - 2. f\ g - 32. g - 64. h - ---- -// Test valid number align values (horizontal and vertical) -// Ref: false -#set enum(number-align: start) -#set enum(number-align: end) -#set enum(number-align: left) -#set enum(number-align: center) -#set enum(number-align: right) -#set enum(number-align: top) -#set enum(number-align: horizon) -#set enum(number-align: bottom) - diff --git a/tests/typ/layout/enum-numbering.typ b/tests/typ/layout/enum-numbering.typ deleted file mode 100644 index 7efe195f..00000000 --- a/tests/typ/layout/enum-numbering.typ +++ /dev/null @@ -1,55 +0,0 @@ -// Test enum numbering styles. - ---- -// Test numbering pattern. -#set enum(numbering: "(1.a.*)") -+ First -+ Second - 2. Nested - + Deep -+ Normal - ---- -// Test full numbering. -#set enum(numbering: "1.a.", full: true) -+ First - + Nested - ---- -// Test numbering with closure. -#enum( - start: 3, - spacing: 0.65em - 3pt, - tight: false, - numbering: n => text( - fill: (red, green, blue).at(calc.rem(n, 3)), - numbering("A", n), - ), - [Red], [Green], [Blue], [Red], -) - ---- -// Test numbering with closure and nested lists. -#set enum(numbering: n => super[#n]) -+ A - + B -+ C - ---- -// Test numbering with closure and nested lists. -#set text(font: "New Computer Modern") -#set enum(numbering: (..args) => math.mat(args.pos()), full: true) -+ A - + B - + C - + D -+ E -+ F - ---- -// Error: 22-24 invalid numbering pattern -#set enum(numbering: "") - ---- -// Error: 22-28 invalid numbering pattern -#set enum(numbering: "(())") diff --git a/tests/typ/layout/enum.typ b/tests/typ/layout/enum.typ deleted file mode 100644 index f9fe2648..00000000 --- a/tests/typ/layout/enum.typ +++ /dev/null @@ -1,48 +0,0 @@ -// Test enumerations. - ---- -#enum[Embrace][Extend][Extinguish] - ---- -0. Before first! -1. First. - 2. Indented - -+ Second - ---- -// Test automatic numbering in summed content. -#for i in range(5) { - [+ #numbering("I", 1 + i)] -} - ---- -// Mix of different lists -- Bullet List -+ Numbered List -/ Term: List - ---- -// In the line. -1.2 \ -This is 0. \ -See 0.3. \ - ---- -// Edge cases. -+ -Empty \ -+Nope \ -a + 0. - ---- -// Test item number overriding. -1. first -+ second -5. fifth - -#enum( - enum.item(1)[First], - [Second], - enum.item(5)[Fifth] -) diff --git a/tests/typ/layout/flow-orphan.typ b/tests/typ/layout/flow-orphan.typ deleted file mode 100644 index 9c5c2399..00000000 --- a/tests/typ/layout/flow-orphan.typ +++ /dev/null @@ -1,30 +0,0 @@ -// Test that lines and headings doesn't become orphan. - ---- -#set page(height: 100pt) -#lorem(12) - -= Introduction -This is the start and it goes on. - ---- -#set page("a8", height: 140pt) -#set text(weight: 700) - -// Fits fully onto the first page. -#set text(blue) -#lorem(27) - -// The first line would fit, but is moved to the second page. -#lorem(20) - -// The second-to-last line is moved to the third page so that the last is isn't -// as lonely. -#set text(maroon) -#lorem(11) - -#lorem(13) - -// All three lines go to the next page. -#set text(olive) -#lorem(10) diff --git a/tests/typ/layout/grid-1.typ b/tests/typ/layout/grid-1.typ deleted file mode 100644 index 411fd8d0..00000000 --- a/tests/typ/layout/grid-1.typ +++ /dev/null @@ -1,41 +0,0 @@ -// Test grid layouts. - ---- -#let cell(width, color) = rect(width: width, height: 2cm, fill: color) -#set page(width: 100pt, height: 140pt) -#grid( - columns: (auto, 1fr, 3fr, 0.25cm, 3%, 2mm + 10%), - cell(0.5cm, rgb("2a631a")), - cell(100%, forest), - cell(100%, conifer), - cell(100%, rgb("ff0000")), - cell(100%, rgb("00ff00")), - cell(80%, rgb("00faf0")), - cell(1cm, rgb("00ff00")), - cell(0.5cm, rgb("2a631a")), - cell(100%, forest), - cell(100%, conifer), - cell(100%, rgb("ff0000")), - cell(100%, rgb("00ff00")), -) - ---- -#set rect(inset: 0pt) -#grid( - columns: (auto, auto, 40%), - column-gutter: 1fr, - row-gutter: 1fr, - rect(fill: eastern)[dddaa aaa aaa], - rect(fill: conifer)[ccc], - rect(fill: rgb("dddddd"))[aaa], -) - ---- -#set page(height: 3cm, margin: 0pt) -#grid( - columns: (1fr,), - rows: (1fr, auto, 2fr), - [], - align(center)[A bit more to the top], - [], -) diff --git a/tests/typ/layout/grid-2.typ b/tests/typ/layout/grid-2.typ deleted file mode 100644 index 66623878..00000000 --- a/tests/typ/layout/grid-2.typ +++ /dev/null @@ -1,29 +0,0 @@ -// Test using the `grid` function to create a finance table. - ---- -#set page(width: 11cm, height: 2.5cm) -#grid( - columns: 5, - column-gutter: (2fr, 1fr, 1fr), - row-gutter: 6pt, - [*Quarter*], - [Expenditure], - [External Revenue], - [Financial ROI], - [_total_], - [*Q1*], - [173,472.57 \$], - [472,860.91 \$], - [51,286.84 \$], - [_350,675.18 \$_], - [*Q2*], - [93,382.12 \$], - [439,382.85 \$], - [-1,134.30 \$], - [_344,866.43 \$_], - [*Q3*], - [96,421.49 \$], - [238,583.54 \$], - [3,497.12 \$], - [_145,659.17 \$_], -) diff --git a/tests/typ/layout/grid-3.typ b/tests/typ/layout/grid-3.typ deleted file mode 100644 index a6c72d6c..00000000 --- a/tests/typ/layout/grid-3.typ +++ /dev/null @@ -1,61 +0,0 @@ -// Test grid cells that overflow to the next region. - ---- -#set page(width: 5cm, height: 3cm) -#grid( - columns: 2, - row-gutter: 8pt, - [Lorem ipsum dolor sit amet. - - Aenean commodo ligula eget dolor. Aenean massa. Penatibus et magnis.], - [Text that is rather short], - [Fireflies], - [Critical], - [Decorum], - [Rampage], -) - ---- -// Test a column that starts overflowing right after another row/column did -// that. -#set page(width: 5cm, height: 2cm) -#grid( - columns: 4 * (1fr,), - row-gutter: 10pt, - column-gutter: (0pt, 10%), - align(top, image("/assets/images/rhino.png")), - align(top, rect(inset: 0pt, fill: eastern, align(right)[LoL])), - [rofl], - [\ A] * 3, - [Ha!\ ] * 3, -) - ---- -// Test two columns in the same row overflowing by a different amount. -#set page(width: 5cm, height: 2cm) -#grid( - columns: 3 * (1fr,), - row-gutter: 8pt, - column-gutter: (0pt, 10%), - [A], [B], [C], - [Ha!\ ] * 6, - [rofl], - [\ A] * 3, - [hello], - [darkness], - [my old] -) - ---- -// Test grid within a grid, overflowing. -#set page(width: 5cm, height: 2.25cm) -#grid( - columns: 4 * (1fr,), - row-gutter: 10pt, - column-gutter: (0pt, 10%), - [A], [B], [C], [D], - grid(columns: 2, [A], [B], [C\ ]*3, [D]), - align(top, rect(inset: 0pt, fill: eastern, align(right)[LoL])), - [rofl], - [E\ ]*4, -) diff --git a/tests/typ/layout/grid-4.typ b/tests/typ/layout/grid-4.typ deleted file mode 100644 index c7ae7649..00000000 --- a/tests/typ/layout/grid-4.typ +++ /dev/null @@ -1,33 +0,0 @@ -// Test relative sizing inside grids. - ---- -// Test that auto and relative columns use the correct base. -#grid( - columns: (auto, 60%), - rows: (auto, auto), - rect(width: 50%, height: 0.5cm, fill: conifer), - rect(width: 100%, height: 0.5cm, fill: eastern), - rect(width: 50%, height: 0.5cm, fill: forest), -) - ---- -// Test that fr columns use the correct base. -#grid( - columns: (1fr,) * 4, - rows: (1cm,), - rect(width: 50%, fill: conifer), - rect(width: 50%, fill: forest), - rect(width: 50%, fill: conifer), - rect(width: 50%, fill: forest), -) - ---- -// Test that all three kinds of rows use the correct bases. -#set page(height: 4cm, margin: 0cm) -#grid( - rows: (1cm, 1fr, 1fr, auto), - rect(height: 50%, width: 100%, fill: conifer), - rect(height: 50%, width: 100%, fill: forest), - rect(height: 50%, width: 100%, fill: conifer), - rect(height: 25%, width: 100%, fill: forest), -) diff --git a/tests/typ/layout/grid-5.typ b/tests/typ/layout/grid-5.typ deleted file mode 100644 index 66272421..00000000 --- a/tests/typ/layout/grid-5.typ +++ /dev/null @@ -1,40 +0,0 @@ - ---- -// Test that trailing linebreak doesn't overflow the region. -#set page(height: 2cm) -#grid[ - Hello \ - Hello \ - Hello \ - - World -] - ---- -// Test that broken cell expands vertically. -#set page(height: 2.25cm) -#grid( - columns: 2, - gutter: 10pt, - align(bottom)[A], - [ - Top - #align(bottom)[ - Bottom \ - Bottom \ - #v(0pt) - Top - ] - ], - align(top)[B], -) - ---- -// Ensure grids expand enough for the given rows. -#grid( - columns: (2em, 2em), - rows: (2em,) * 4, - fill: red, - stroke: aqua, - [a] -) diff --git a/tests/typ/layout/grid-auto-shrink.typ b/tests/typ/layout/grid-auto-shrink.typ deleted file mode 100644 index 4d9ef0d8..00000000 --- a/tests/typ/layout/grid-auto-shrink.typ +++ /dev/null @@ -1,12 +0,0 @@ -// Test iterative auto column shrinking. - ---- -#set page(width: 210mm - 2 * 2.5cm + 2 * 10pt) -#set text(11pt) -#table( - columns: 4, - [Hello!], - [Hello there, my friend!], - [Hello there, my friends! Hi!], - [Hello there, my friends! Hi! What is going on right now?], -) diff --git a/tests/typ/layout/grid-cell.typ b/tests/typ/layout/grid-cell.typ deleted file mode 100644 index a812fefc..00000000 --- a/tests/typ/layout/grid-cell.typ +++ /dev/null @@ -1,133 +0,0 @@ -// Test basic styling using the grid.cell element. - ---- -// Cell override -#grid( - align: left, - fill: red, - stroke: blue, - inset: 5pt, - columns: 2, - [AAAAA], [BBBBB], - [A], [B], - grid.cell(align: right)[C], [D], - align(right)[E], [F], - align(horizon)[G], [A\ A\ A], - grid.cell(align: horizon)[G2], [A\ A\ A], - grid.cell(inset: 0pt)[I], [F], - [H], grid.cell(fill: blue)[J] -) - ---- -// Cell show rule -#show grid.cell: it => [Zz] - -#grid( - align: left, - fill: red, - stroke: blue, - inset: 5pt, - columns: 2, - [AAAAA], [BBBBB], - [A], [B], - grid.cell(align: right)[C], [D], - align(right)[E], [F], - align(horizon)[G], [A\ A\ A] -) - ---- -#show grid.cell: it => (it.align, it.fill) -#grid( - align: left, - row-gutter: 5pt, - [A], - grid.cell(align: right)[B], - grid.cell(fill: aqua)[B], -) - ---- -// Cell set rules -#set grid.cell(align: center) -#show grid.cell: it => (it.align, it.fill, it.inset) -#set grid.cell(inset: 20pt) -#grid( - align: left, - row-gutter: 5pt, - [A], - grid.cell(align: right)[B], - grid.cell(fill: aqua)[B], -) - ---- -// Test folding per-cell properties (align and inset) -#grid( - columns: (1fr, 1fr), - rows: (2.5em, auto), - align: right, - inset: 5pt, - fill: (x, y) => (green, aqua).at(calc.rem(x + y, 2)), - [Top], grid.cell(align: bottom)[Bot], - grid.cell(inset: (bottom: 0pt))[Bot], grid.cell(inset: (bottom: 0pt))[Bot] -) - ---- -// Test overriding outside alignment -#set align(bottom + right) -#grid( - columns: (1fr, 1fr), - rows: 2em, - align: auto, - fill: green, - [BR], [BR], - grid.cell(align: left, fill: aqua)[BL], grid.cell(align: top, fill: red.lighten(50%))[TR] -) - ---- -// First doc example -#grid( - columns: 2, - fill: red, - align: left, - inset: 5pt, - [ABC], [ABC], - grid.cell(fill: blue)[C], [D], - grid.cell(align: center)[E], [F], - [G], grid.cell(inset: 0pt)[H] -) - ---- -#{ - show grid.cell: emph - grid( - columns: 2, - gutter: 3pt, - [Hello], [World], - [Sweet], [Italics] - ) -} - ---- -// Style based on position -#{ - show grid.cell: it => { - if it.y == 0 { - strong(it) - } else if it.x == 1 { - emph(it) - } else { - it - } - } - grid( - columns: 3, - gutter: 3pt, - [Name], [Age], [Info], - [John], [52], [Nice], - [Mary], [50], [Cool], - [Jake], [49], [Epic] - ) -} - ---- -// Error: 7-19 cannot use `table.cell` as a grid cell; use `grid.cell` instead -#grid(table.cell[]) diff --git a/tests/typ/layout/grid-colspan.typ b/tests/typ/layout/grid-colspan.typ deleted file mode 100644 index 1bdadcf1..00000000 --- a/tests/typ/layout/grid-colspan.typ +++ /dev/null @@ -1,141 +0,0 @@ -#grid( - columns: 4, - fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, - inset: 5pt, - align: center, - grid.cell(colspan: 4)[*Full Header*], - grid.cell(colspan: 2, fill: orange)[*Half*], - grid.cell(colspan: 2, fill: orange.darken(10%))[*Half*], - [*A*], [*B*], [*C*], [*D*], - [1], [2], [3], [4], - [5], grid.cell(colspan: 3, fill: orange.darken(10%))[6], - grid.cell(colspan: 2, fill: orange)[7], [8], [9], - [10], grid.cell(colspan: 2, fill: orange.darken(10%))[11], [12] -) - -#table( - columns: 4, - fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, - inset: 5pt, - align: center, - table.cell(colspan: 4)[*Full Header*], - table.cell(colspan: 2, fill: orange)[*Half*], - table.cell(colspan: 2, fill: orange.darken(10%))[*Half*], - [*A*], [*B*], [*C*], [*D*], - [1], [2], [3], [4], - [5], table.cell(colspan: 3, fill: orange.darken(10%))[6], - table.cell(colspan: 2, fill: orange)[7], [8], [9], - [10], table.cell(colspan: 2, fill: orange.darken(10%))[11], [12] -) - ---- -#grid( - columns: 4, - fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, - inset: 5pt, - align: center, - gutter: 3pt, - grid.cell(colspan: 4)[*Full Header*], - grid.cell(colspan: 2, fill: orange)[*Half*], - grid.cell(colspan: 2, fill: orange.darken(10%))[*Half*], - [*A*], [*B*], [*C*], [*D*], - [1], [2], [3], [4], - [5], grid.cell(colspan: 3, fill: orange.darken(10%))[6], - grid.cell(colspan: 2, fill: orange)[7], [8], [9], - [10], grid.cell(colspan: 2, fill: orange.darken(10%))[11], [12] -) - -#table( - columns: 4, - fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, - inset: 5pt, - align: center, - gutter: 3pt, - table.cell(colspan: 4)[*Full Header*], - table.cell(colspan: 2, fill: orange)[*Half*], - table.cell(colspan: 2, fill: orange.darken(10%))[*Half*], - [*A*], [*B*], [*C*], [*D*], - [1], [2], [3], [4], - [5], table.cell(colspan: 3, fill: orange.darken(10%))[6], - table.cell(colspan: 2, fill: orange)[7], [8], [9], - [10], table.cell(colspan: 2, fill: orange.darken(10%))[11], [12] -) - ---- -#set page(width: 300pt) -#table( - columns: (2em, 2em, auto, auto), - stroke: 5pt, - [A], [B], [C], [D], - table.cell(colspan: 4, lorem(20)), - [A], table.cell(colspan: 2)[BCBCBCBC], [D] -) - ---- -// Error: 3:8-3:32 cell's colspan would cause it to exceed the available column(s) -// Hint: 3:8-3:32 try placing the cell in another position or reducing its colspan -#grid( - columns: 3, - [a], grid.cell(colspan: 3)[b] -) - ---- -// Error: 4:8-4:32 cell would span a previously placed cell at column 2, row 0 -// Hint: 4:8-4:32 try specifying your cells in a different order or reducing the cell's rowspan or colspan -#grid( - columns: 3, - grid.cell(x: 2, y: 0)[x], - [a], grid.cell(colspan: 2)[b] -) - ---- -// Colspan over all fractional columns shouldn't expand auto columns on finite pages -#table( - columns: (1fr, 1fr, auto), - [A], [B], [C], - [D], [E], [F] -) -#table( - columns: (1fr, 1fr, auto), - table.cell(colspan: 3, lorem(8)), - [A], [B], [C], - [D], [E], [F] -) - ---- -// Colspan over only some fractional columns will not trigger the heuristic, and -// the auto column will expand more than it should. The table looks off, as a result. -#table( - columns: (1fr, 1fr, auto), - [], table.cell(colspan: 2, lorem(8)), - [A], [B], [C], - [D], [E], [F] -) - ---- -// On infinite pages, colspan over all fractional columns SHOULD expand auto columns -#set page(width: auto) -#table( - columns: (1fr, 1fr, auto), - [A], [B], [C], - [D], [E], [F] -) -#table( - columns: (1fr, 1fr, auto), - table.cell(colspan: 3, lorem(8)), - [A], [B], [C], - [D], [E], [F] -) - ---- -// Test multiple regions -#set page(height: 5em) -#grid( - stroke: red, - fill: aqua, - columns: 4, - [a], [b], [c], [d], - [a], grid.cell(colspan: 2)[e, f, g, h, i], [f], - [e], [g], grid.cell(colspan: 2)[eee\ e\ e\ e], - grid.cell(colspan: 4)[eeee e e e] -) diff --git a/tests/typ/layout/grid-footers-1.typ b/tests/typ/layout/grid-footers-1.typ deleted file mode 100644 index c7a59e60..00000000 --- a/tests/typ/layout/grid-footers-1.typ +++ /dev/null @@ -1,192 +0,0 @@ -#set page(width: auto, height: 15em) -#set text(6pt) -#set table(inset: 2pt, stroke: 0.5pt) -#table( - columns: 5, - align: center + horizon, - table.header( - table.cell(colspan: 5)[*Cool Zone*], - table.cell(stroke: red)[*Name*], table.cell(stroke: aqua)[*Number*], [*Data 1*], [*Data 2*], [*Etc*], - table.hline(start: 2, end: 3, stroke: yellow) - ), - ..range(0, 5).map(i => ([John \##i], table.cell(stroke: green)[123], table.cell(stroke: blue)[456], [789], [?], table.hline(start: 4, end: 5, stroke: red))).flatten(), - table.footer( - table.hline(start: 2, end: 3, stroke: yellow), - table.cell(stroke: red)[*Name*], table.cell(stroke: aqua)[*Number*], [*Data 1*], [*Data 2*], [*Etc*], - table.cell(colspan: 5)[*Cool Zone*] - ) -) - ---- -// Gutter & no repetition -#set page(width: auto, height: 16em) -#set text(6pt) -#set table(inset: 2pt, stroke: 0.5pt) -#table( - columns: 5, - gutter: 2pt, - align: center + horizon, - table.header( - table.cell(colspan: 5)[*Cool Zone*], - table.cell(stroke: red)[*Name*], table.cell(stroke: aqua)[*Number*], [*Data 1*], [*Data 2*], [*Etc*], - table.hline(start: 2, end: 3, stroke: yellow) - ), - ..range(0, 5).map(i => ([John \##i], table.cell(stroke: green)[123], table.cell(stroke: blue)[456], [789], [?], table.hline(start: 4, end: 5, stroke: red))).flatten(), - table.footer( - repeat: false, - table.hline(start: 2, end: 3, stroke: yellow), - table.cell(stroke: red)[*Name*], table.cell(stroke: aqua)[*Number*], [*Data 1*], [*Data 2*], [*Etc*], - table.cell(colspan: 5)[*Cool Zone*] - ) -) - ---- -#table( - table.header(table.cell(stroke: red)[Hello]), - table.footer(table.cell(stroke: aqua)[Bye]), -) - ---- -#table( - gutter: 3pt, - table.header(table.cell(stroke: red)[Hello]), - table.footer(table.cell(stroke: aqua)[Bye]), -) - ---- -// Footer's top stroke should win when repeated, but lose at the last page. -#set page(height: 10em) -#table( - stroke: green, - table.header(table.cell(stroke: red)[Hello]), - table.cell(stroke: yellow)[Hi], - table.cell(stroke: yellow)[Bye], - table.cell(stroke: yellow)[Ok], - table.footer[Bye], -) - ---- -// Relative lengths -#set page(height: 10em) -#table( - rows: (30%, 30%, auto), - [C], - [C], - table.footer[*A*][*B*], -) - ---- -#grid( - grid.footer(grid.cell(y: 2)[b]), - grid.cell(y: 0)[a], - grid.cell(y: 1)[c], -) - ---- -// Ensure footer properly expands -#grid( - columns: 2, - [a], [], - [b], [], - grid.cell(x: 1, y: 3, rowspan: 4)[b], - grid.cell(y: 2, rowspan: 2)[a], - grid.footer(), - grid.cell(y: 4)[d], - grid.cell(y: 5)[e], - grid.cell(y: 6)[f], -) - ---- -// Error: 2:3-2:19 footer must end at the last row -#grid( - grid.footer([a]), - [b], -) - ---- -// Error: 3:3-3:19 footer must end at the last row -#grid( - columns: 2, - grid.footer([a]), - [b], -) - ---- -// Error: 4:3-4:19 footer would conflict with a cell placed before it at column 1 row 0 -// Hint: 4:3-4:19 try reducing that cell's rowspan or moving the footer -#grid( - columns: 2, - grid.header(), - grid.footer([a]), - grid.cell(x: 1, y: 0, rowspan: 2)[a], -) - ---- -// Error: 4:3-4:19 cannot have more than one footer -#grid( - [a], - grid.footer([a]), - grid.footer([b]), -) - ---- -// Error: 3:3-3:20 cannot use `table.footer` as a grid footer; use `grid.footer` instead -#grid( - [a], - table.footer([a]), -) - ---- -// Error: 3:3-3:19 cannot use `grid.footer` as a table footer; use `table.footer` instead -#table( - [a], - grid.footer([a]), -) - ---- -// Error: 14-28 cannot place a grid footer within another footer or header -#grid.header(grid.footer[a]) - ---- -// Error: 14-29 cannot place a table footer within another footer or header -#grid.header(table.footer[a]) - ---- -// Error: 15-29 cannot place a grid footer within another footer or header -#table.header(grid.footer[a]) - ---- -// Error: 15-30 cannot place a table footer within another footer or header -#table.header(table.footer[a]) - ---- -// Error: 14-28 cannot place a grid footer within another footer or header -#grid.footer(grid.footer[a]) - ---- -// Error: 14-29 cannot place a table footer within another footer or header -#grid.footer(table.footer[a]) - ---- -// Error: 15-29 cannot place a grid footer within another footer or header -#table.footer(grid.footer[a]) - ---- -// Error: 15-30 cannot place a table footer within another footer or header -#table.footer(table.footer[a]) - ---- -// Error: 14-28 cannot place a grid header within another header or footer -#grid.footer(grid.header[a]) - ---- -// Error: 14-29 cannot place a table header within another header or footer -#grid.footer(table.header[a]) - ---- -// Error: 15-29 cannot place a grid header within another header or footer -#table.footer(grid.header[a]) - ---- -// Error: 15-30 cannot place a table header within another header or footer -#table.footer(table.header[a]) diff --git a/tests/typ/layout/grid-footers-2.typ b/tests/typ/layout/grid-footers-2.typ deleted file mode 100644 index df333434..00000000 --- a/tests/typ/layout/grid-footers-2.typ +++ /dev/null @@ -1,31 +0,0 @@ -#set page(height: 17em) -#table( - rows: (auto, 2.5em, auto), - table.header[*Hello*][*World*], - block(width: 2em, height: 10em, fill: red), - table.footer[*Bye*][*World*], -) - ---- -// Rowspan sizing algorithm doesn't do the best job at non-contiguous content -// ATM. -#set page(height: 20em) - -#table( - rows: (auto, 2.5em, 2em, auto, 5em, 2em, 2.5em), - table.header[*Hello*][*World*], - table.cell(rowspan: 3, lorem(20)), - table.footer[*Ok*][*Bye*], -) - ---- -// This should look right -#set page(height: 20em) - -#table( - rows: (auto, 2.5em, 2em, auto), - gutter: 3pt, - table.header[*Hello*][*World*], - table.cell(rowspan: 3, lorem(20)), - table.footer[*Ok*][*Bye*], -) diff --git a/tests/typ/layout/grid-footers-3.typ b/tests/typ/layout/grid-footers-3.typ deleted file mode 100644 index 070500f1..00000000 --- a/tests/typ/layout/grid-footers-3.typ +++ /dev/null @@ -1,44 +0,0 @@ -// Test lack of space for header + text. -#set page(height: 9em + 2.5em + 1.5em) - -#table( - rows: (auto, 2.5em, auto, auto, 10em, 2.5em, auto), - gutter: 3pt, - table.header[*Hello*][*World*], - table.cell(rowspan: 3, lorem(30)), - table.footer[*Ok*][*Bye*], -) - ---- -// Orphan header prevention test -#set page(height: 13em) -#v(8em) -#grid( - columns: 3, - gutter: 5pt, - grid.header( - [*Mui*], [*A*], grid.cell(rowspan: 2, fill: orange)[*B*], - [*Header*], [*Header* #v(0.1em)], - ), - ..([Test], [Test], [Test]) * 7, - grid.footer( - [*Mui*], [*A*], grid.cell(rowspan: 2, fill: orange)[*B*], - [*Footer*], [*Footer* #v(0.1em)], - ), -) - ---- -// Empty footer should just be a repeated blank row -#set page(height: 8em) -#table( - columns: 4, - align: center + horizon, - table.header(), - ..range(0, 2).map(i => ( - [John \##i], - table.cell(stroke: green)[123], - table.cell(stroke: blue)[456], - [789] - )).flatten(), - table.footer(), -) diff --git a/tests/typ/layout/grid-footers-4.typ b/tests/typ/layout/grid-footers-4.typ deleted file mode 100644 index b6d978e9..00000000 --- a/tests/typ/layout/grid-footers-4.typ +++ /dev/null @@ -1,42 +0,0 @@ -// When a footer has a rowspan with an empty row, it should be displayed -// properly -#set page(height: 14em, width: auto) - -#let count = counter("g") -#table( - rows: (auto, 2em, auto, auto), - table.header( - [eeec], - table.cell(rowspan: 2, count.step() + count.display()), - ), - [d], - block(width: 5em, fill: yellow, lorem(7)), - [d], - table.footer( - [eeec], - table.cell(rowspan: 2, count.step() + count.display()), - ) -) -#count.display() - ---- -// Nested table with footer should repeat both footers -#set page(height: 10em, width: auto) -#table( - table( - [a\ b\ c\ d], - table.footer[b], - ), - table.footer[a], -) - ---- -#set page(height: 12em, width: auto) -#table( - [a\ b\ c\ d], - table.footer(table( - [c], - [d], - table.footer[b], - )) -) diff --git a/tests/typ/layout/grid-footers-5.typ b/tests/typ/layout/grid-footers-5.typ deleted file mode 100644 index 16da940a..00000000 --- a/tests/typ/layout/grid-footers-5.typ +++ /dev/null @@ -1,87 +0,0 @@ -// General footer-only tests -#set page(height: 9em) -#table( - columns: 2, - [a], [], - [b], [], - [c], [], - [d], [], - [e], [], - table.footer( - [*Ok*], table.cell(rowspan: 2)[test], - [*Thanks*] - ) -) - ---- -#set page(height: 5em) -#table( - table.footer[a][b][c] -) - ---- -#table(table.footer[a][b][c]) - -#table( - gutter: 3pt, - table.footer[a][b][c] -) - ---- -// Test footer stroke priority edge case -#set page(height: 10em) -#table( - columns: 2, - stroke: black, - ..(table.cell(stroke: aqua)[d],) * 8, - table.footer( - table.cell(rowspan: 2, colspan: 2)[a], - [c], [d] - ) -) - ---- -// Footer should appear at the bottom. Red line should be above the footer. -// Green line should be on the left border. -#set page(margin: 2pt) -#set text(6pt) -#table( - columns: 2, - inset: 1.5pt, - table.cell(y: 0)[a], - table.cell(x: 1, y: 1)[a], - table.cell(y: 2)[a], - table.footer( - table.hline(stroke: red), - table.vline(stroke: green), - [b], - ), - table.cell(x: 1, y: 3)[c] -) - ---- -// Table should be just one row. [c] appears at the third column. -#set page(margin: 2pt) -#set text(6pt) -#table( - columns: 3, - inset: 1.5pt, - table.cell(y: 0)[a], - table.footer( - table.hline(stroke: red), - table.hline(y: 1, stroke: aqua), - table.cell(y: 0)[b], - [c] - ) -) - ---- -// Footer should go below the rowspans. -#set page(margin: 2pt) -#set text(6pt) -#table( - columns: 2, - inset: 1.5pt, - table.cell(rowspan: 2)[a], table.cell(rowspan: 2)[b], - table.footer() -) diff --git a/tests/typ/layout/grid-headers-1.typ b/tests/typ/layout/grid-headers-1.typ deleted file mode 100644 index ac998029..00000000 --- a/tests/typ/layout/grid-headers-1.typ +++ /dev/null @@ -1,162 +0,0 @@ -#set page(width: auto, height: 12em) -#table( - columns: 5, - align: center + horizon, - table.header( - table.cell(colspan: 5)[*Cool Zone*], - table.cell(stroke: red)[*Name*], table.cell(stroke: aqua)[*Number*], [*Data 1*], [*Data 2*], [*Etc*], - table.hline(start: 2, end: 3, stroke: yellow) - ), - ..range(0, 6).map(i => ([John \##i], table.cell(stroke: green)[123], table.cell(stroke: blue)[456], [789], [?], table.hline(start: 4, end: 5, stroke: red))).flatten() -) - ---- -// Disable repetition -#set page(width: auto, height: 12em) -#table( - columns: 5, - align: center + horizon, - table.header( - table.cell(colspan: 5)[*Cool Zone*], - table.cell(stroke: red)[*Name*], table.cell(stroke: aqua)[*Number*], [*Data 1*], [*Data 2*], [*Etc*], - table.hline(start: 2, end: 3, stroke: yellow), - repeat: false - ), - ..range(0, 6).map(i => ([John \##i], table.cell(stroke: green)[123], table.cell(stroke: blue)[456], [789], [?], table.hline(start: 4, end: 5, stroke: red))).flatten() -) - ---- -#set page(width: auto, height: 12em) -#table( - columns: 5, - align: center + horizon, - gutter: 3pt, - table.header( - table.cell(colspan: 5)[*Cool Zone*], - table.cell(stroke: red)[*Name*], table.cell(stroke: aqua)[*Number*], [*Data 1*], [*Data 2*], [*Etc*], - table.hline(start: 2, end: 3, stroke: yellow), - ), - ..range(0, 6).map(i => ([John \##i], table.cell(stroke: green)[123], table.cell(stroke: blue)[456], [789], [?], table.hline(start: 4, end: 5, stroke: red))).flatten() -) - ---- -// Relative lengths -#set page(height: 10em) -#table( - rows: (30%, 30%, auto), - table.header( - [*A*], - [*B*] - ), - [C], - [C] -) - ---- -#grid( - grid.cell(y: 1)[a], - grid.header(grid.cell(y: 0)[b]), - grid.cell(y: 2)[c] -) - ---- -// When the header is the last grid child, it shouldn't include the gutter row -// after it, because there is none. -#grid( - columns: 2, - gutter: 3pt, - grid.header( - [a], [b], - [c], [d] - ) -) - ---- -#set page(height: 14em) -#let t(n) = table( - columns: 3, - align: center + horizon, - gutter: 3pt, - table.header( - table.cell(colspan: 3)[*Cool Zone #n*], - [*Name*], [*Num*], [*Data*] - ), - ..range(0, 5).map(i => ([\##i], table.cell(stroke: green)[123], table.cell(stroke: blue)[456])).flatten() -) -#grid( - gutter: 3pt, - t(0), - t(1) -) - ---- -// Test line positioning in header -#table( - columns: 3, - stroke: none, - table.hline(stroke: red, end: 2), - table.vline(stroke: red, end: 3), - table.header( - table.hline(stroke: aqua, start: 2), - table.vline(stroke: aqua, start: 3), [*A*], table.hline(stroke: orange), table.vline(stroke: orange), [*B*], - [*C*], [*D*] - ), - [a], [b], - [c], [d], - [e], [f] -) - ---- -// Error: 3:3-3:19 header must start at the first row -// Hint: 3:3-3:19 remove any rows before the header -#grid( - [a], - grid.header([b]) -) - ---- -// Error: 4:3-4:19 header must start at the first row -// Hint: 4:3-4:19 remove any rows before the header -#grid( - columns: 2, - [a], - grid.header([b]) -) - ---- -// Error: 3:3-3:19 cannot have more than one header -#grid( - grid.header([a]), - grid.header([b]), - [a], -) - ---- -// Error: 2:3-2:20 cannot use `table.header` as a grid header; use `grid.header` instead -#grid( - table.header([a]), - [a], -) - ---- -// Error: 2:3-2:19 cannot use `grid.header` as a table header; use `table.header` instead -#table( - grid.header([a]), - [a], -) - ---- -// Error: 14-28 cannot place a grid header within another header or footer -#grid.header(grid.header[a]) - ---- -// Error: 14-29 cannot place a table header within another header or footer -#grid.header(table.header[a]) - ---- -// Error: 15-29 cannot place a grid header within another header or footer -#table.header(grid.header[a]) - ---- -// Error: 15-30 cannot place a table header within another header or footer -#table.header(table.header[a]) diff --git a/tests/typ/layout/grid-headers-2.typ b/tests/typ/layout/grid-headers-2.typ deleted file mode 100644 index 75c9b330..00000000 --- a/tests/typ/layout/grid-headers-2.typ +++ /dev/null @@ -1,52 +0,0 @@ -#set page(height: 15em) -#table( - rows: (auto, 2.5em, auto), - table.header( - [*Hello*], - [*World*] - ), - block(width: 2em, height: 20em, fill: red) -) - ---- -// Rowspan sizing algorithm doesn't do the best job at non-contiguous content -// ATM. -#set page(height: 15em) - -#table( - rows: (auto, 2.5em, 2em, auto, 5em), - table.header( - [*Hello*], - [*World*] - ), - table.cell(rowspan: 3, lorem(40)) -) - ---- -// Rowspan sizing algorithm doesn't do the best job at non-contiguous content -// ATM. -#set page(height: 15em) - -#table( - rows: (auto, 2.5em, 2em, auto, 5em), - gutter: 3pt, - table.header( - [*Hello*], - [*World*] - ), - table.cell(rowspan: 3, lorem(40)) -) - ---- -// This should look right -#set page(height: 15em) - -#table( - rows: (auto, 2.5em, 2em, auto), - gutter: 3pt, - table.header( - [*Hello*], - [*World*] - ), - table.cell(rowspan: 3, lorem(40)) -) diff --git a/tests/typ/layout/grid-headers-3.typ b/tests/typ/layout/grid-headers-3.typ deleted file mode 100644 index e7437cf7..00000000 --- a/tests/typ/layout/grid-headers-3.typ +++ /dev/null @@ -1,35 +0,0 @@ -// Test lack of space for header + text. -#set page(height: 9em) - -#table( - rows: (auto, 2.5em, auto, auto, 10em), - gutter: 3pt, - table.header( - [*Hello*], - [*World*] - ), - table.cell(rowspan: 3, lorem(80)) -) - ---- -// Orphan header prevention test -#set page(height: 12em) -#v(8em) -#grid( - columns: 3, - grid.header( - [*Mui*], [*A*], grid.cell(rowspan: 2, fill: orange)[*B*], - [*Header*], [*Header* #v(0.1em)] - ), - ..([Test], [Test], [Test]) * 20 -) - ---- -// Empty header should just be a repeated blank row -#set page(height: 12em) -#table( - columns: 4, - align: center + horizon, - table.header(), - ..range(0, 4).map(i => ([John \##i], table.cell(stroke: green)[123], table.cell(stroke: blue)[456], [789])).flatten() -) diff --git a/tests/typ/layout/grid-headers-4.typ b/tests/typ/layout/grid-headers-4.typ deleted file mode 100644 index 6ab0d612..00000000 --- a/tests/typ/layout/grid-headers-4.typ +++ /dev/null @@ -1,112 +0,0 @@ -// When a header has a rowspan with an empty row, it should be displayed -// properly -#set page(height: 10em) - -#let count = counter("g") -#table( - rows: (auto, 2em, auto, auto), - table.header( - [eeec], - table.cell(rowspan: 2, count.step() + count.display()), - ), - [d], - block(width: 5em, fill: yellow, lorem(15)), - [d] -) -#count.display() - ---- -// Ensure header expands to fit cell placed in it after its declaration -#set page(height: 10em) -#table( - columns: 2, - table.header( - [a], [b], - [c], - ), - table.cell(x: 1, y: 1, rowspan: 2, lorem(80)) -) - ---- -// Nested table with header should repeat both headers -#set page(height: 10em) -#table( - table.header( - [a] - ), - table( - table.header( - [b] - ), - [a\ b\ c\ d] - ) -) - ---- -#set page(height: 12em) -#table( - table.header( - table( - table.header( - [b] - ), - [c], - [d] - ) - ), - [a\ b] -) - ---- -// Test header stroke priority edge case (last header row removed) -#set page(height: 8em) -#table( - columns: 2, - stroke: black, - gutter: (auto, 3pt), - table.header( - [c], [d], - ), - ..(table.cell(stroke: aqua)[d],) * 8, -) - ---- -// Yellow line should be kept here -#set text(6pt) -#table( - column-gutter: 3pt, - inset: 1pt, - table.header( - [a], - table.hline(stroke: yellow), - ), - table.cell(rowspan: 2)[b] -) - ---- -// Red line should be kept here -#set page(height: 6em) -#set text(6pt) -#table( - column-gutter: 3pt, - inset: 1pt, - table.header( - table.hline(stroke: red, position: bottom), - [a], - ), - [a], - table.cell(stroke: aqua)[b] -) - ---- -#set page(height: 7em) -#set text(6pt) -#let full-block = block(width: 2em, height: 100%, fill: red) -#table( - columns: 3, - inset: 1.5pt, - table.header( - [a], full-block, table.cell(rowspan: 2, full-block), - [b] - ) -) diff --git a/tests/typ/layout/grid-positioning.typ b/tests/typ/layout/grid-positioning.typ deleted file mode 100644 index 228fadf7..00000000 --- a/tests/typ/layout/grid-positioning.typ +++ /dev/null @@ -1,205 +0,0 @@ -// Test cell positioning in grids. - ---- -#{ - show grid.cell: it => (it.x, it.y) - grid( - columns: 2, - inset: 5pt, - fill: aqua, - gutter: 3pt, - [Hello], [World], - [Sweet], [Home] - ) -} -#{ - show table.cell: it => pad(rest: it.inset)[#(it.x, it.y)] - table( - columns: 2, - gutter: 3pt, - [Hello], [World], - [Sweet], [Home] - ) -} - ---- -// Positioning cells in a different order than they appear -#grid( - columns: 2, - [A], [B], - grid.cell(x: 1, y: 2)[C], grid.cell(x: 0, y: 2)[D], - grid.cell(x: 1, y: 1)[E], grid.cell(x: 0, y: 1)[F], -) - ---- -// Creating more rows by positioning out of bounds -#grid( - columns: 3, - rows: 1.5em, - inset: 5pt, - fill: (x, y) => if (x, y) == (0, 0) { blue } else if (x, y) == (2, 3) { red } else { green }, - [A], - grid.cell(x: 2, y: 3)[B] -) - -#table( - columns: (3em, 1em, 3em), - rows: 1.5em, - inset: (top: 0pt, bottom: 0pt, rest: 5pt), - fill: (x, y) => if (x, y) == (0, 0) { blue } else if (x, y) == (2, 3) { red } else { green }, - align: (x, y) => (left, center, right).at(x), - [A], - table.cell(x: 2, y: 3)[B] -) - ---- -// Error: 3:3-3:42 attempted to place a second cell at column 0, row 0 -// Hint: 3:3-3:42 try specifying your cells in a different order -#grid( - [A], - grid.cell(x: 0, y: 0)[This shall error] -) - ---- -// Error: 3:3-3:43 attempted to place a second cell at column 0, row 0 -// Hint: 3:3-3:43 try specifying your cells in a different order -#table( - [A], - table.cell(x: 0, y: 0)[This shall error] -) - ---- -// Automatic position cell skips custom position cell -#grid( - grid.cell(x: 0, y: 0)[This shall not error], - [A] -) - ---- -// Error: 4:3-4:36 cell could not be placed at invalid column 2 -#grid( - columns: 2, - [A], - grid.cell(x: 2)[This shall error] -) - ---- -// Partial positioning -#grid( - columns: 3, - rows: 1.5em, - inset: 5pt, - fill: aqua, - [A], grid.cell(y: 1, fill: green)[B], [C], grid.cell(x: auto, y: 1, fill: green)[D], [E], - grid.cell(y: 2, fill: green)[F], grid.cell(x: 0, fill: orange)[G], grid.cell(x: 0, y: auto, fill: orange)[H], - grid.cell(x: 1, fill: orange)[I] -) - -#table( - columns: 3, - rows: 1.5em, - inset: 5pt, - fill: aqua, - [A], table.cell(y: 1, fill: green)[B], [C], table.cell(x: auto, y: 1, fill: green)[D], [E], - table.cell(y: 2, fill: green)[F], table.cell(x: 0, fill: orange)[G], table.cell(x: 0, y: auto, fill: orange)[H], - table.cell(x: 1, fill: orange)[I] -) - ---- -// Error: 4:3-4:21 cell could not be placed in row 0 because it was full -// Hint: 4:3-4:21 try specifying your cells in a different order -#grid( - columns: 2, - [A], [B], - grid.cell(y: 0)[C] -) - ---- -// Error: 4:3-4:22 cell could not be placed in row 0 because it was full -// Hint: 4:3-4:22 try specifying your cells in a different order -#table( - columns: 2, - [A], [B], - table.cell(y: 0)[C] -) - ---- -// Doc example 1 -#set page(width: auto) -#show grid.cell: it => { - if it.y == 0 { - set text(white) - strong(it) - } else { - // For the second row and beyond, we will write the day number for each - // cell. - - // In general, a cell's index is given by cell.x + columns * cell.y. - // Days start in the second grid row, so we subtract 1 row. - // But the first day is day 1, not day 0, so we add 1. - let day = it.x + 7 * (it.y - 1) + 1 - if day <= 31 { - // Place the day's number at the top left of the cell. - // Only if the day is valid for this month (not 32 or higher). - place(top + left, dx: 2pt, dy: 2pt, text(8pt, red.darken(40%))[#day]) - } - it - } -} - -#grid( - fill: (x, y) => if y == 0 { gray.darken(50%) }, - columns: (30pt,) * 7, - rows: (auto, 30pt), - // Events will be written at the bottom of each day square. - align: bottom, - inset: 5pt, - stroke: (thickness: 0.5pt, dash: "densely-dotted"), - - [Sun], [Mon], [Tue], [Wed], [Thu], [Fri], [Sat], - - // This event will occur on the first Friday (sixth column). - grid.cell(x: 5, fill: yellow.darken(10%))[Call], - - // This event will occur every Monday (second column). - // We have to repeat it 5 times so it occurs every week. - ..(grid.cell(x: 1, fill: red.lighten(50%))[Meet],) * 5, - - // This event will occur at day 19. - grid.cell(x: 4, y: 3, fill: orange.lighten(25%))[Talk], - - // These events will occur at the second week, where available. - grid.cell(y: 2, fill: aqua)[Chat], - grid.cell(y: 2, fill: aqua)[Walk], -) - ---- -// Doc example 2 -#set page(width: auto) -#show table.cell: it => { - if it.x == 0 or it.y == 0 { - set text(white) - strong(it) - } else if it.body == [] { - // Replace empty cells with 'N/A' - pad(rest: it.inset)[_N/A_] - } else { - it - } -} - -#table( - fill: (x, y) => if x == 0 or y == 0 { gray.darken(50%) }, - columns: 4, - [], [Exam 1], [Exam 2], [Exam 3], - ..([John], [Mary], [Jake], [Robert]).map(table.cell.with(x: 0)), - - // Mary got grade A on Exam 3. - table.cell(x: 3, y: 2, fill: green)[A], - - // Everyone got grade A on Exam 2. - ..(table.cell(x: 2, fill: green)[A],) * 4, - - // Robert got grade B on other exams. - ..(table.cell(y: 4, fill: aqua)[B],) * 2, -) diff --git a/tests/typ/layout/grid-rowspan-basic.typ b/tests/typ/layout/grid-rowspan-basic.typ deleted file mode 100644 index bbd1c047..00000000 --- a/tests/typ/layout/grid-rowspan-basic.typ +++ /dev/null @@ -1,252 +0,0 @@ -#grid( - columns: 4, - fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, - inset: 5pt, - align: center, - grid.cell(rowspan: 2, fill: orange)[*Left*], - [Right A], [Right A], [Right A], - [Right B], grid.cell(colspan: 2, rowspan: 2, fill: orange.darken(10%))[B Wide], - [Left A], [Left A], - [Left B], [Left B], grid.cell(colspan: 2, rowspan: 3, fill: orange)[Wide and Long] -) - -#table( - columns: 4, - fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, - inset: 5pt, - align: center, - table.cell(rowspan: 2, fill: orange)[*Left*], - [Right A], [Right A], [Right A], - [Right B], table.cell(colspan: 2, rowspan: 2, fill: orange.darken(10%))[B Wide], - [Left A], [Left A], - [Left B], [Left B], table.cell(colspan: 2, rowspan: 3, fill: orange)[Wide and Long] -) - ---- -#grid( - columns: 4, - fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, - inset: 5pt, - align: center, - gutter: 3pt, - grid.cell(rowspan: 2, fill: orange)[*Left*], - [Right A], [Right A], [Right A], - [Right B], grid.cell(colspan: 2, rowspan: 2, fill: orange.darken(10%))[B Wide], - [Left A], [Left A], - [Left B], [Left B], grid.cell(colspan: 2, rowspan: 3, fill: orange)[Wide and Long] -) - -#table( - columns: 4, - fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, - inset: 5pt, - align: center, - gutter: 3pt, - table.cell(rowspan: 2, fill: orange)[*Left*], - [Right A], [Right A], [Right A], - [Right B], table.cell(colspan: 2, rowspan: 2, fill: orange.darken(10%))[B Wide], - [Left A], [Left A], - [Left B], [Left B], table.cell(colspan: 2, rowspan: 3, fill: orange)[Wide and Long] -) - ---- -// Fixed-size rows -#set page(height: 10em) -#grid( - columns: 2, - rows: 1.5em, - fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, - grid.cell(rowspan: 3)[R1], [b], - [c], - [d], - [e], [f], - grid.cell(rowspan: 5)[R2], [h], - [i], - [j], - [k], - [l], - [m], [n] -) - ---- -// Cell coordinate tests -#set page(height: 10em) -#show table.cell: it => [(#it.x, #it.y)] -#table( - columns: 3, - fill: red, - [a], [b], table.cell(rowspan: 2)[c], - table.cell(colspan: 2)[d], - table.cell(colspan: 3, rowspan: 10)[a], - table.cell(colspan: 2)[b], -) -#table( - columns: 3, - gutter: 3pt, - fill: red, - [a], [b], table.cell(rowspan: 2)[c], - table.cell(colspan: 2)[d], - table.cell(colspan: 3, rowspan: 9)[a], - table.cell(colspan: 2)[b], -) - ---- -// Auto row expansion -#set page(height: 10em) -#grid( - columns: (1em, 1em), - rows: (0.5em, 0.5em, auto), - fill: orange, - gutter: 3pt, - grid.cell(rowspan: 4, [x x x x] + place(bottom)[*Bot*]), - [a], - [b], - [c], - [d] -) - ---- -// Excessive rowspan (no gutter) -#set page(height: 10em) -#table( - columns: 4, - fill: red, - [a], [b], table.cell(rowspan: 2)[c], [d], - table.cell(colspan: 2, stroke: (bottom: aqua + 2pt))[e], table.cell(stroke: (bottom: aqua))[f], - table.cell(colspan: 2, rowspan: 10)[R1], table.cell(colspan: 2, rowspan: 10)[R2], - [b], -) - ---- -// Excessive rowspan (with gutter) -#set page(height: 10em) -#table( - columns: 4, - gutter: 3pt, - fill: red, - [a], [b], table.cell(rowspan: 2)[c], [d], - table.cell(colspan: 2, stroke: (bottom: aqua + 2pt))[e], table.cell(stroke: (bottom: aqua))[f], - table.cell(colspan: 2, rowspan: 10)[R1], table.cell(colspan: 2, rowspan: 10)[R2], - [b], -) - ---- -// Fractional rows -// They cause the auto row to expand more than needed. -#set page(height: 10em) -#grid( - fill: red, - gutter: 3pt, - columns: 3, - rows: (1em, auto, 1fr), - [a], [b], grid.cell(rowspan: 3, block(height: 4em, width: 1em, fill: orange)), - [c], [d], - [e], [f] -) - ---- -// Fractional rows -#set page(height: 10em) -#grid( - fill: red, - gutter: 3pt, - columns: 3, - rows: (1fr, auto, 1em), - [a], [b], grid.cell(rowspan: 3, block(height: 4em, width: 1em, fill: orange)), - [c], [d], - [e], [f] -) - ---- -// Cell order -#let count = counter("count") -#show grid.cell: it => { - count.step() - count.display() -} - -#grid( - columns: (2em,) * 3, - stroke: aqua, - rows: 1.2em, - fill: (x, y) => if calc.odd(x + y) { red } else { orange }, - [a], grid.cell(rowspan: 2)[b], grid.cell(rowspan: 2)[c], - [d], - grid.cell(rowspan: 2)[f], [g], [h], - [i], [j], - [k], [l], [m], - grid.cell(rowspan: 2)[n], [o], [p], - [q], [r], - [s], [t], [u] -) - ---- -#table( - columns: 3, - rows: (auto, auto, auto, 2em), - gutter: 3pt, - table.cell(rowspan: 4)[a \ b\ c\ d\ e], [c], [d], - [e], table.cell(breakable: false, rowspan: 2)[f], - [g] -) - ---- -// Test cell breakability -#show grid.cell: it => { - assert.eq(it.breakable, (it.x, it.y) != (0, 6) and (it.y in (2, 5, 6) or (it.x, it.y) in ((0, 1), (2, 3), (1, 7)))) - it.breakable -} -#grid( - columns: 3, - rows: (6pt, 1fr, auto, 1%, 1em, auto, auto, 0.2in), - row-gutter: (0pt, 0pt, 0pt, auto), - [a], [b], [c], - grid.cell(rowspan: 3)[d], [e], [f], - [g], [h], - [i], grid.cell(rowspan: 2)[j], - [k], - grid.cell(y: 5)[l], - grid.cell(y: 6, breakable: false)[m], grid.cell(y: 6, breakable: true)[n], - grid.cell(y: 7, breakable: false)[o], grid.cell(y: 7, breakable: true)[p], grid.cell(y: 7, breakable: auto)[q] -) - ---- -#table( - columns: 2, - table.cell(stroke: (bottom: red))[a], [b], - table.hline(stroke: green), - table.cell(stroke: (top: yellow, left: green, right: aqua, bottom: blue), colspan: 1, rowspan: 2)[d], table.cell(colspan: 1, rowspan: 2)[e], - [f], - [g] -) - ---- -#table( - columns: 2, - gutter: 3pt, - table.cell(stroke: (bottom: red))[a], [b], - table.hline(stroke: green), - table.cell(stroke: (top: yellow, left: green, right: aqua, bottom: blue), colspan: 1, rowspan: 2)[d], table.cell(colspan: 1, rowspan: 2)[e], - [f], - [g] -) - ---- -// Block below shouldn't expand to the end of the page, but stay within its -// rows' boundaries. -#set page(height: 9em) -#table( - rows: (1em, 1em, 1fr, 1fr, auto), - table.cell(rowspan: 2, block(width: 2em, height: 100%, fill: red)), - table.cell(rowspan: 2, block(width: 2em, height: 100%, fill: red)), - [a] -) - ---- -#set page(height: 7em) -#table( - columns: 3, - [], [], table.cell(breakable: true, rowspan: 2, block(width: 2em, height: 100%, fill: red)), - table.cell(breakable: false, block(width: 2em, height: 100%, fill: red)), - table.cell(breakable: false, rowspan: 2, block(width: 2em, height: 100%, fill: red)), -) diff --git a/tests/typ/layout/grid-rowspan-split-1.typ b/tests/typ/layout/grid-rowspan-split-1.typ deleted file mode 100644 index e247fa80..00000000 --- a/tests/typ/layout/grid-rowspan-split-1.typ +++ /dev/null @@ -1,89 +0,0 @@ -// Rowspan split tests - ---- -#set page(height: 10em) -#table( - columns: 2, - rows: (auto, auto, 3em), - fill: red, - [a], table.cell(rowspan: 3, block(width: 50%, height: 10em, fill: orange) + place(bottom)[*ZD*]), - [e], - [f] -) - ---- -#set page(height: 10em) -#table( - columns: 2, - rows: (auto, auto, 3em), - row-gutter: 1em, - fill: red, - [a], table.cell(rowspan: 3, block(width: 50%, height: 10em, fill: orange) + place(bottom)[*ZD*]), - [e], - [f] -) - ---- -#set page(height: 5em) -#table( - columns: 2, - fill: red, - inset: 0pt, - table.cell(fill: orange, rowspan: 10, place(bottom)[*Z*] + [x\ ] * 10 + place(bottom)[*ZZ*]), - ..([y],) * 10, - [a], [b], -) - ---- -#set page(height: 5em) -#table( - columns: 2, - fill: red, - inset: 0pt, - gutter: 2pt, - table.cell(fill: orange, rowspan: 10, place(bottom)[*Z*] + [x\ ] * 10 + place(bottom)[*ZZ*]), - ..([y],) * 10, - [a], [b], -) - ---- -#set page(height: 5em) -#table( - columns: 2, - fill: red, - inset: 0pt, - table.cell(fill: orange, rowspan: 10, breakable: false, place(bottom)[*Z*] + [x\ ] * 10 + place(bottom)[*ZZ*]), - ..([y],) * 10, - [a], [b], -) - ---- -#set page(height: 5em) -#table( - columns: 2, - fill: red, - inset: 0pt, - gutter: 2pt, - table.cell(fill: orange, rowspan: 10, breakable: false, place(bottom)[*Z*] + [x\ ] * 10 + place(bottom)[*ZZ*]), - ..([y],) * 10, - [a], [b], -) - ---- -#set page(height: 5em) -#grid( - columns: 2, - stroke: red, - inset: 5pt, - grid.cell(rowspan: 5)[a\ b\ c\ d\ e] -) - ---- -#set page(height: 5em) -#table( - columns: 2, - gutter: 3pt, - stroke: red, - inset: 5pt, - table.cell(rowspan: 5)[a\ b\ c\ d\ e] -) diff --git a/tests/typ/layout/grid-rowspan-split-2.typ b/tests/typ/layout/grid-rowspan-split-2.typ deleted file mode 100644 index 189feed3..00000000 --- a/tests/typ/layout/grid-rowspan-split-2.typ +++ /dev/null @@ -1,37 +0,0 @@ -// Rowspan split without ending at the auto row - ---- -#set page(height: 6em) -#table( - rows: (4em,) * 7 + (auto,) + (4em,) * 7, - columns: 2, - column-gutter: 1em, - row-gutter: (1em, 2em) * 4, - fill: (x, y) => if calc.odd(x + y) { orange.lighten(20%) } else { red }, - table.cell(rowspan: 15, [a \ ] * 15), - [] * 15 -) - ---- -#set page(height: 6em) -#table( - rows: (4em,) * 7 + (auto,) + (4em,) * 7, - columns: 2, - column-gutter: 1em, - row-gutter: (1em, 2em) * 4, - fill: (x, y) => if calc.odd(x + y) { green } else { green.darken(40%) }, - table.cell(rowspan: 15, block(fill: blue, width: 2em, height: 4em * 14 + 3em)), - [] * 15 -) - ---- -#set page(height: 6em) -#table( - rows: (3em,) * 15, - columns: 2, - column-gutter: 1em, - row-gutter: (1em, 2em) * 4, - fill: (x, y) => if calc.odd(x + y) { aqua } else { blue }, - table.cell(breakable: true, rowspan: 15, [a \ ] * 15), - [] * 15 -) diff --git a/tests/typ/layout/grid-rowspan-split-3.typ b/tests/typ/layout/grid-rowspan-split-3.typ deleted file mode 100644 index 4c3ce7d8..00000000 --- a/tests/typ/layout/grid-rowspan-split-3.typ +++ /dev/null @@ -1,108 +0,0 @@ -// Some splitting corner cases - ---- -// Inside the larger rowspan's range, there's an unbreakable rowspan and a -// breakable rowspan. This should work normally. -// The auto row will also expand ignoring the last fractional row. -#set page(height: 10em) -#table( - gutter: 0.5em, - columns: 2, - rows: (2em,) * 10 + (auto, auto, 2em, 1fr), - fill: (_, y) => if calc.even(y) { aqua } else { blue }, - table.cell(rowspan: 14, block(width: 2em, height: 2em * 10 + 2em + 5em, fill: red)[]), - ..([a],) * 5, - table.cell(rowspan: 3)[a\ b], - table.cell(rowspan: 5, [a\ b\ c\ d\ e\ f\ g\ h]), - [z] -) - ---- -// Inset moving to next region bug -#set page(width: 10cm, height: 2.5cm, margin: 0.5cm) -#set text(size: 11pt) -#table( - columns: (1fr, 1fr, 1fr), - [A], - [B], - [C], - [D], - table.cell(rowspan: 2, lorem(4)), - [E], - [F], - [G], -) - ---- -// Second lorem must be sent to the next page, too big -#set page(width: 10cm, height: 9cm, margin: 1cm) -#set text(size: 11pt) -#table( - columns: (1fr, 1fr, 1fr), - align: center, - rows: (4cm, auto), - [A], [B], [C], - table.cell(rowspan: 4, breakable: false, lorem(10)), - [D], - table.cell(rowspan: 2, breakable: false, lorem(20)), - [E], -) - ---- -// Auto row must expand properly in both cases -#set text(10pt) -#show table.cell: it => if it.x == 0 { it } else { layout(size => size.height) } -#table( - columns: 2, - rows: (1em, auto, 2em, 3em, 4em), - gutter: 3pt, - table.cell(rowspan: 5, block(fill: orange, height: 15em)[a]), - [b], - [c], - [d], - [e], - [f] -) - -#table( - columns: 2, - rows: (1em, auto, 2em, 3em, 4em), - gutter: 3pt, - table.cell(rowspan: 5, breakable: false, block(fill: orange, height: 15em)[a]), - [b], - [c], - [d], - [e], - [f] -) - ---- -// Expanding on unbreakable auto row -#set page(height: 7em, margin: (bottom: 2em)) -#grid( - columns: 2, - rows: (1em, 1em, auto, 1em, 1em, 1em), - fill: (x, y) => if x == 0 { aqua } else { blue }, - stroke: black, - gutter: 2pt, - grid.cell(rowspan: 5, block(height: 10em)[a]), - [a], - [b], - grid.cell(breakable: false, v(3em) + [c]), - [d], - [e], - [f], [g] -) - ---- -#show table.cell.where(x: 0): strong -#show table.cell.where(y: 0): strong -#set page(height: 13em) -#let lets-repeat(thing, n) = ((thing + colbreak(),) * (calc.max(0, n - 1)) + (thing,)).join() -#table( - columns: 4, - fill: (x, y) => if x == 0 or y == 0 { gray }, - [], [Test 1], [Test 2], [Test 3], - table.cell(rowspan: 15, align: horizon, lets-repeat((rotate(-90deg, reflow: true)[*All Tests*]), 3)), - ..([123], [456], [789]) * 15 -) diff --git a/tests/typ/layout/grid-rtl.typ b/tests/typ/layout/grid-rtl.typ deleted file mode 100644 index cea67d96..00000000 --- a/tests/typ/layout/grid-rtl.typ +++ /dev/null @@ -1,195 +0,0 @@ -// Test RTL grid. - ---- -#set text(dir: rtl) -- מימין לשמאל - ---- -#set text(dir: rtl) -#table(columns: 2)[A][B][C][D] - ---- -// Test interaction between RTL and colspans -#set text(dir: rtl) -#grid( - columns: 4, - fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, - inset: 5pt, - align: center, - grid.cell(colspan: 4)[*Full Header*], - grid.cell(colspan: 2, fill: orange)[*Half*], - grid.cell(colspan: 2, fill: orange.darken(10%))[*Half*], - [*A*], [*B*], [*C*], [*D*], - [1], [2], [3], [4], - [5], grid.cell(colspan: 3, fill: orange.darken(10%))[6], - grid.cell(colspan: 2, fill: orange)[7], [8], [9], - [10], grid.cell(colspan: 2, fill: orange.darken(10%))[11], [12] -) - -#grid( - columns: 4, - fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, - inset: 5pt, - align: center, - gutter: 3pt, - grid.cell(colspan: 4)[*Full Header*], - grid.cell(colspan: 2, fill: orange)[*Half*], - grid.cell(colspan: 2, fill: orange.darken(10%))[*Half*], - [*A*], [*B*], [*C*], [*D*], - [1], [2], [3], [4], - [5], grid.cell(colspan: 3, fill: orange.darken(10%))[6], - grid.cell(colspan: 2, fill: orange)[7], [8], [9], - [10], grid.cell(colspan: 2, fill: orange.darken(10%))[11], [12] -) - ---- -#set text(dir: rtl) -#table( - columns: 4, - fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, - inset: 5pt, - align: center, - table.cell(colspan: 4)[*Full Header*], - table.cell(colspan: 2, fill: orange)[*Half*], - table.cell(colspan: 2, fill: orange.darken(10%))[*Half*], - [*A*], [*B*], [*C*], [*D*], - [1], [2], [3], [4], - [5], table.cell(colspan: 3, fill: orange.darken(10%))[6], - table.cell(colspan: 2, fill: orange)[7], [8], [9], - [10], table.cell(colspan: 2, fill: orange.darken(10%))[11], [12] -) - -#table( - columns: 4, - fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, - inset: 5pt, - align: center, - gutter: 3pt, - table.cell(colspan: 4)[*Full Header*], - table.cell(colspan: 2, fill: orange)[*Half*], - table.cell(colspan: 2, fill: orange.darken(10%))[*Half*], - [*A*], [*B*], [*C*], [*D*], - [1], [2], [3], [4], - [5], table.cell(colspan: 3, fill: orange.darken(10%))[6], - table.cell(colspan: 2, fill: orange)[7], [8], [9], - [10], table.cell(colspan: 2, fill: orange.darken(10%))[11], [12] -) - ---- -// Test multiple regions -#set page(height: 5em) -#set text(dir: rtl) -#grid( - stroke: red, - fill: aqua, - columns: 4, - [a], [b], [c], [d], - [a], grid.cell(colspan: 2)[e, f, g, h, i], [f], - [e], [g], grid.cell(colspan: 2)[eee\ e\ e\ e], - grid.cell(colspan: 4)[eeee e e e] -) - ---- -// Test left and right for vlines in RTL -#set text(dir: rtl) -#grid( - columns: 3, - inset: 5pt, - grid.vline(stroke: red, position: left), grid.vline(stroke: green, position: right), [a], - grid.vline(stroke: red, position: left), grid.vline(stroke: 2pt, position: right), [b], - grid.vline(stroke: red, position: left), grid.vline(stroke: 2pt, position: right), [c], - grid.vline(stroke: aqua, position: right) -) - -#grid( - columns: 3, - inset: 5pt, - gutter: 3pt, - grid.vline(stroke: green, position: left), grid.vline(stroke: red, position: right), [a], - grid.vline(stroke: blue, position: left), grid.vline(stroke: red, position: right), [b], - grid.vline(stroke: blue, position: left), grid.vline(stroke: red, position: right), [c], - grid.vline(stroke: 2pt, position: right) -) - -#grid( - columns: 3, - inset: 5pt, - grid.vline(stroke: green, position: start), grid.vline(stroke: red, position: end), [a], - grid.vline(stroke: 2pt, position: start), grid.vline(stroke: red, position: end), [b], - grid.vline(stroke: 2pt, position: start), grid.vline(stroke: red, position: end), [c], - grid.vline(stroke: 2pt, position: start) -) - -#grid( - columns: 3, - inset: 5pt, - gutter: 3pt, - grid.vline(stroke: green, position: start), grid.vline(stroke: red, position: end), [a], - grid.vline(stroke: blue, position: start), grid.vline(stroke: red, position: end), [b], - grid.vline(stroke: blue, position: start), grid.vline(stroke: red, position: end), [c], - grid.vline(stroke: 2pt, position: start) -) - ---- -// Error: 3:8-3:34 cannot place vertical line at the 'end' position of the end border (x = 1) -// Hint: 3:8-3:34 set the line's position to 'start' or place it at a smaller 'x' index -#set text(dir: rtl) -#grid( - [a], grid.vline(position: left) -) - ---- -#set text(dir: rtl) - -#grid( - columns: 4, - fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, - inset: 5pt, - align: center, - grid.cell(rowspan: 2, fill: orange)[*Left*], - [Right A], [Right A], [Right A], - [Right B], grid.cell(colspan: 2, rowspan: 2, fill: orange.darken(10%))[B Wide], - [Left A], [Left A], - [Left B], [Left B], grid.cell(colspan: 2, rowspan: 3, fill: orange)[Wide and Long] -) - -#table( - columns: 4, - fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) }, - inset: 5pt, - align: center, - gutter: 3pt, - table.cell(rowspan: 2, fill: orange)[*Left*], - [Right A], [Right A], [Right A], - [Right B], table.cell(colspan: 2, rowspan: 2, fill: orange.darken(10%))[B Wide], - [Left A], [Left A], - [Left B], [Left B], table.cell(colspan: 2, rowspan: 3, fill: orange)[Wide and Long] -) - ---- -#set page(height: 10em) -#set text(dir: rtl) -#table( - columns: 2, - rows: (auto, auto, 3em), - row-gutter: 1em, - fill: red, - [a], table.cell(rowspan: 3, block(width: 50%, height: 10em, fill: orange) + place(bottom)[*ZD*]), - [e], - [f] -) - ---- -// Headers -#set page(height: 15em) -#set text(dir: rtl) -#table( - columns: 5, - align: center + horizon, - table.header( - table.cell(colspan: 5)[*Cool Zone*], - table.cell(stroke: red)[*N1*], table.cell(stroke: aqua)[*N2*], [*D1*], [*D2*], [*Etc*], - table.hline(start: 2, end: 3, stroke: yellow) - ), - ..range(0, 10).map(i => ([\##i], table.cell(stroke: green)[123], table.cell(stroke: blue)[456], [789], [?], table.hline(start: 4, end: 5, stroke: red))).flatten() -) diff --git a/tests/typ/layout/grid-stroke.typ b/tests/typ/layout/grid-stroke.typ deleted file mode 100644 index 35a65ae6..00000000 --- a/tests/typ/layout/grid-stroke.typ +++ /dev/null @@ -1,434 +0,0 @@ -#let double-line = pattern(size: (1.5pt, 1.5pt), { - place(line(stroke: .6pt, start: (0%, 50%), end: (100%, 50%))) -}) - -#table( - stroke: (_, y) => if y != 1 { (bottom: black) }, - columns: 3, - table.cell(colspan: 3, align: center)[*Epic Table*], - align(center)[*Name*], align(center)[*Age*], align(center)[*Data*], - table.hline(stroke: (paint: double-line, thickness: 2pt)), - [John], [30], [None], - [Martha], [20], [A], - [Joseph], [35], [D] -) - ---- -// Test folding -#set grid(stroke: red) -#set grid(stroke: 5pt) - -#grid( - inset: 10pt, - columns: 2, - stroke: stroke(dash: "loosely-dotted"), - grid.vline(start: 2, end: 3, stroke: (paint: green, dash: none)), - [a], [b], - grid.hline(end: 1, stroke: blue), - [c], [d], - [e], grid.cell(stroke: aqua)[f] -) - ---- -// Test set rules on cells and folding -#set table.cell(stroke: 4pt) -#set table.cell(stroke: blue) -#set table.hline(stroke: red) -#set table.hline(stroke: 0.75pt) -#set table.vline(stroke: 0.75pt) -#set table.vline(stroke: aqua) - -#table( - columns: 3, - gutter: 3pt, - inset: 5pt, - [a], [b], table.vline(position: end), [c], - [d], [e], [f], - table.hline(position: bottom), - [g], [h], [i], -) - ---- -// Test stroke field on cell show rules -#set grid.cell(stroke: (x: 4pt)) -#set grid.cell(stroke: (x: blue)) -#show grid.cell: it => { - test(it.stroke, (left: stroke(paint: blue, thickness: 4pt, dash: "loosely-dotted"), right: blue + 4pt, top: stroke(thickness: 1pt), bottom: none)) - it -} -#grid( - stroke: (left: (dash: "loosely-dotted")), - inset: 5pt, - grid.hline(stroke: red), - grid.cell(stroke: (top: 1pt))[a], grid.vline(stroke: yellow), -) - ---- -#table( - columns: 3, - [a], table.cell(colspan: 2)[b c], - table.cell(stroke: blue)[d], [e], [f], - [g], [h], table.cell(stroke: (left: yellow, top: green, right: aqua, bottom: red))[i], - [j], [k], [l], - table.cell(stroke: 3pt)[m], [n], table.cell(stroke: (dash: "loosely-dotted"))[o], -) - ---- -// Test per-column stroke array -#let t = table( - columns: 3, - stroke: (red, blue, green), - [a], [b], [c], - [d], [e], [f], - [h], [i], [j], -) -#t -#set text(dir: rtl) -#t - ---- -#grid( - columns: 3, - inset: 3pt, - stroke: (x, _) => (right: (5pt, (dash: "dotted")).at(calc.rem(x, 2)), bottom: (dash: "densely-dotted")), - grid.vline(x: 0, stroke: red), - grid.vline(x: 1, stroke: red), - grid.vline(x: 2, stroke: red), - grid.vline(x: 3, stroke: red), - grid.hline(y: 0, end: 1, stroke: blue), - grid.hline(y: 1, end: 1, stroke: blue), - grid.cell[a], - [b], [c] -) - ---- -#set page(height: 5em) -#table( - columns: 3, - inset: 3pt, - table.hline(y: 0, end: none, stroke: 3pt + blue), - table.vline(x: 0, end: none, stroke: 3pt + green), - table.hline(y: 5, end: none, stroke: 3pt + red), - table.vline(x: 3, end: none, stroke: 3pt + yellow), - [a], [b], [c], - [a], [b], [c], - [a], [b], [c], - [a], [b], [c], - [a], [b], [c], -) - ---- -// Automatically positioned lines -// Plus stroke thickness ordering -#table( - columns: 3, - table.hline(stroke: red + 5pt), - table.vline(stroke: blue + 5pt), - table.vline(stroke: 2pt), - [a], - table.vline(x: 1, stroke: aqua + 5pt), - [b], - table.vline(stroke: aqua + 5pt), - [c], - table.vline(stroke: yellow + 5.2pt), - table.hline(stroke: green + 5pt), - [a], [b], [c], - [a], table.hline(stroke: green + 2pt), table.vline(stroke: 2pt), [b], [c], -) - ---- -// Line specification order priority -// The last line should be blue, not red. -// The middle aqua line should be gone due to the 'none' override. -#grid( - columns: 2, - inset: 2pt, - grid.hline(y: 2, stroke: red + 5pt), - grid.vline(), - [a], [b], - grid.hline(stroke: red), - grid.hline(stroke: none), - [c], grid.cell(stroke: (top: aqua))[d], - grid.hline(stroke: blue), -) - ---- -// Position: bottom and position: end with gutter should have a visible effect -// of moving the lines after the next track. -#table( - columns: 3, - gutter: 3pt, - stroke: blue, - table.hline(end: 2, stroke: red), - table.hline(end: 2, stroke: aqua, position: bottom), - table.vline(end: 2, stroke: green), [a], table.vline(end: 2, stroke: green), table.vline(end: 2, position: end, stroke: orange), [b], table.vline(end: 2, stroke: aqua, position: end), table.vline(end: 2, stroke: green), [c], table.vline(end: 2, stroke: green), - [d], [e], [f], - table.hline(end: 2, stroke: red), - [g], [h], [ie], - table.hline(end: 2, stroke: green), -) - ---- -// Using position: bottom and position: end without gutter should be the same -// as placing a line after the next track. -#table( - columns: 3, - stroke: blue, - table.hline(end: 2, stroke: red), - table.hline(end: 2, stroke: aqua, position: bottom), - table.vline(end: 2, stroke: green), [a], table.vline(end: 2, stroke: green), [b], table.vline(end: 2, stroke: aqua, position: end), table.vline(end: 2, stroke: green), [c], table.vline(end: 2, stroke: green), - table.hline(end: 2, stroke: 5pt), - [d], [e], [f], - table.hline(end: 2, stroke: red), - [g], [h], [i], - table.hline(end: 2, stroke: red), -) - ---- -// Test left and right for grid vlines. -#grid( - columns: 3, - inset: 5pt, - grid.vline(stroke: green, position: left), grid.vline(stroke: red, position: right), [a], - grid.vline(stroke: 2pt, position: left), grid.vline(stroke: red, position: right), [b], - grid.vline(stroke: 2pt, position: left), grid.vline(stroke: red, position: right), [c], - grid.vline(stroke: 2pt, position: left) -) - -#grid( - columns: 3, - inset: 5pt, - gutter: 3pt, - grid.vline(stroke: green, position: left), grid.vline(stroke: red, position: right), [a], - grid.vline(stroke: blue, position: left), grid.vline(stroke: red, position: right), [b], - grid.vline(stroke: blue, position: left), grid.vline(stroke: red, position: right), [c], - grid.vline(stroke: 2pt, position: left) -) - ---- -// Test left and right for table vlines. -#table( - columns: 3, - inset: 5pt, - table.vline(stroke: green, position: left), table.vline(stroke: red, position: right), [a], - table.vline(stroke: 2pt, position: left), table.vline(stroke: red, position: right), [b], - table.vline(stroke: 2pt, position: left), table.vline(stroke: red, position: right), [c], - table.vline(stroke: 2pt, position: left) -) - -#table( - columns: 3, - inset: 5pt, - gutter: 3pt, - table.vline(stroke: green, position: left), table.vline(stroke: red, position: right), [a], - table.vline(stroke: blue, position: left), table.vline(stroke: red, position: right), [b], - table.vline(stroke: blue, position: left), table.vline(stroke: red, position: right), [c], - table.vline(stroke: 2pt, position: left) -) - ---- -// Hlines and vlines should always appear on top of cell strokes. -#table( - columns: 3, - stroke: aqua, - table.vline(stroke: red, position: end), [a], table.vline(stroke: red), [b], [c], - table.cell(stroke: blue)[d], [e], [f], - table.hline(stroke: red), - [g], table.cell(stroke: blue)[h], [i], -) - -#table( - columns: 3, - gutter: 3pt, - stroke: aqua, - table.vline(stroke: red, position: end), [a], table.vline(stroke: red), [b], [c], - table.cell(stroke: blue)[d], [e], [f], - table.hline(stroke: red), - [g], table.cell(stroke: blue)[h], [i], -) - ---- -// Ensure cell stroke overrides always appear on top. -#table( - columns: 2, - stroke: black, - table.cell(stroke: red)[a], [b], - [c], [d], -) - -#table( - columns: 2, - table.cell(stroke: red)[a], [b], - [c], [d], -) - ---- -// Error: 7:3-7:32 cannot place horizontal line at the 'bottom' position of the bottom border (y = 2) -// Hint: 7:3-7:32 set the line's position to 'top' or place it at a smaller 'y' index -#table( - columns: 2, - [a], [b], - [c], [d], - table.hline(stroke: aqua), - table.hline(position: top), - table.hline(position: bottom) -) - ---- -// Test partial border line overrides -#set page(width: auto, height: 7em, margin: (bottom: 1em)) -#table( - columns: 4, - stroke: (x, y) => if y == 0 or y == 4 { orange } else { aqua }, - table.hline(stroke: blue, start: 1, end: 2), table.cell(stroke: red, v(3em)), table.cell(stroke: blue)[b], table.cell(stroke: green)[c], [M], - [a], [b], [c], [M], - [d], [e], [f], [M], - [g], [h], [i], [M], - table.cell(stroke: red)[a], table.cell(stroke: blue)[b], table.cell(stroke: green)[c], [M], - table.hline(stroke: blue, start: 1, end: 2), -) - ---- -// - Vline should be placed after the colspan. -// - Hline should be placed under the full-width rowspan. -#table( - columns: 3, - rows: 1.25em, - inset: 1pt, - stroke: none, - table.cell(colspan: 2)[a], table.vline(stroke: red), table.hline(stroke: blue), [b], - [c], [d], [e], - table.cell(colspan: 3, rowspan: 2)[a], table.vline(stroke: blue), table.hline(stroke: red) -) - ---- -// Red line should be above [c] (hline skips the shortest rowspan). -#set text(6pt) -#table( - rows: 1em, - columns: 2, - inset: 1.5pt, - table.cell(rowspan: 3)[a], table.cell(rowspan: 2)[b], - table.hline(stroke: red), - [c] -) - ---- -// Error: 8:3-8:32 cannot place horizontal line at the 'bottom' position of the bottom border (y = 2) -// Hint: 8:3-8:32 set the line's position to 'top' or place it at a smaller 'y' index -#table( - columns: 2, - gutter: 3pt, - [a], [b], - [c], [d], table.vline(stroke: red), - table.hline(stroke: aqua), - table.hline(position: top), - table.hline(position: bottom) -) - ---- -// Error: 6:3-6:28 cannot place vertical line at the 'end' position of the end border (x = 2) -// Hint: 6:3-6:28 set the line's position to 'start' or place it at a smaller 'x' index -#grid( - columns: 2, - [a], [b], - grid.vline(stroke: aqua), - grid.vline(position: start), - grid.vline(position: end) -) - ---- -// Error: 7:3-7:28 cannot place vertical line at the 'end' position of the end border (x = 2) -// Hint: 7:3-7:28 set the line's position to 'start' or place it at a smaller 'x' index -#grid( - columns: 2, - gutter: 3pt, - [a], [b], - grid.vline(stroke: aqua), - grid.vline(position: start), - grid.vline(position: end) -) - ---- -// Error: 4:3-4:19 cannot place horizontal line at invalid row 3 -#grid( - [a], - [b], - grid.hline(y: 3) -) - ---- -// Error: 5:3-5:19 cannot place horizontal line at invalid row 3 -#grid( - gutter: 3pt, - [a], - [b], - grid.hline(y: 3) -) - ---- -// Error: 4:3-4:20 cannot place vertical line at invalid column 3 -#table( - columns: 2, - [a], [b], - table.vline(x: 3) -) - ---- -// Error: 5:3-5:20 cannot place vertical line at invalid column 3 -#table( - columns: 2, - gutter: 3pt, - [a], [b], - table.vline(x: 3) -) - ---- -// Error: 7-20 cannot use `table.hline` as a grid line; use `grid.hline` instead -#grid(table.hline()) - ---- -// Error: 7-20 cannot use `table.vline` as a grid line; use `grid.vline` instead -#grid(table.vline()) - ---- -// Error: 8-20 cannot use `grid.hline` as a table line; use `table.hline` instead -#table(grid.hline()) - ---- -// Error: 8-20 cannot use `grid.vline` as a table line; use `table.vline` instead -#table(grid.vline()) - ---- -// Error: 3:3-3:31 line cannot end before it starts -#grid( - columns: 3, - grid.hline(start: 2, end: 1), - [a], [b], [c], -) - ---- -// Error: 3:3-3:32 line cannot end before it starts -#table( - columns: 3, - table.vline(start: 2, end: 1), - [a], [b], [c], - [d], [e], [f], - [g], [h], [i], -) - ---- -// Error: 24-31 expected `top` or `bottom`, found horizon -#table.hline(position: horizon) - ---- -// Error: 24-30 expected `start`, `left`, `right`, or `end`, found center -#table.vline(position: center) - ---- -// Error: 24-29 expected `top` or `bottom`, found right -#table.hline(position: right) - ---- -// Error: 24-27 expected `start`, `left`, `right`, or `end`, found top -#table.vline(position: top) diff --git a/tests/typ/layout/grid-styling.typ b/tests/typ/layout/grid-styling.typ deleted file mode 100644 index f83c3cc4..00000000 --- a/tests/typ/layout/grid-styling.typ +++ /dev/null @@ -1,160 +0,0 @@ -// Test grid styling options. - ---- -#set page(height: 70pt) -#set grid(fill: (x, y) => if calc.even(x + y) { rgb("aaa") }) - -#grid( - columns: (1fr,) * 3, - stroke: 2pt + rgb("333"), - [A], [B], [C], [], [], [D \ E \ F \ \ \ G], [H], -) - ---- -#grid(columns: 3, stroke: none, fill: green, [A], [B], [C]) - ---- -// Test general alignment. -#grid( - columns: 3, - align: left, - [Hello], [Hello], [Hello], - [A], [B], [C], -) - -// Test alignment with a function. -#grid( - columns: 3, - align: (x, y) => (left, center, right).at(x), - [Hello], [Hello], [Hello], - [A], [B], [C], -) - -// Test alignment with array. -#grid( - columns: (1fr, 1fr, 1fr), - align: (left, center, right), - [A], [B], [C] -) - -// Test empty array. -#set align(center) -#grid( - columns: (1fr, 1fr, 1fr), - align: (), - [A], [B], [C] -) - -a - ---- -// Test inset. -#grid( - columns: (1fr,) * 3, - stroke: 2pt + rgb("333"), - inset: 5pt, - [A], [B], [C], [], [], [D \ E \ F \ \ \ G], [H], -) - -#grid( - columns: 3, - inset: 10pt, - fill: blue, - [A], [B], [C] -) - -#grid( - columns: 3, - inset: (y: 10pt), - [A], [B], [C] -) - -#grid( - columns: 3, - inset: (left: 20pt, rest: 10pt), - stroke: 3pt + red, - [A], [B], [C] -) - -#grid( - columns: 2, - inset: ( - left: 20pt, - right: 5pt, - top: 10pt, - bottom: 3pt, - ), - [A], - [B], -) - -#grid( - columns: 3, - fill: (x, y) => (if y == 0 { aqua } else { orange }).darken(x * 15%), - inset: (x, y) => (left: if x == 0 { 0pt } else { 5pt }, right: if x == 0 { 5pt } else { 0pt }, y: if y == 0 { 0pt } else { 5pt }), - [A], [B], [C], - [A], [B], [C], -) - -#grid( - columns: 3, - inset: (0pt, 5pt, 10pt), - fill: (x, _) => aqua.darken(x * 15%), - [A], [B], [C], -) - ---- -// Test inset folding -#set grid(inset: 10pt) -#set grid(inset: (left: 0pt)) - -#grid( - fill: red, - inset: (right: 0pt), - grid.cell(inset: (top: 0pt))[a] -) - ---- -// Test interaction with gutters. -#grid( - columns: (3em, 3em), - fill: (x, y) => (red, blue).at(calc.rem(x, 2)), - align: (x, y) => (left, right).at(calc.rem(y, 2)), - [A], [B], - [C], [D], - [E], [F], - [G], [H] -) - -#grid( - columns: (3em, 3em), - fill: (x, y) => (red, blue).at(calc.rem(x, 2)), - align: (x, y) => (left, right).at(calc.rem(y, 2)), - row-gutter: 5pt, - [A], [B], - [C], [D], - [E], [F], - [G], [H] -) - -#grid( - columns: (3em, 3em), - fill: (x, y) => (red, blue).at(calc.rem(x, 2)), - align: (x, y) => (left, right).at(calc.rem(y, 2)), - column-gutter: 5pt, - [A], [B], - [C], [D], - [E], [F], - [G], [H] -) - -#grid( - columns: (3em, 3em), - fill: (x, y) => (red, blue).at(calc.rem(x, 2)), - align: (x, y) => (left, right).at(calc.rem(y, 2)), - gutter: 5pt, - [A], [B], - [C], [D], - [E], [F], - [G], [H] -) diff --git a/tests/typ/layout/hide.typ b/tests/typ/layout/hide.typ deleted file mode 100644 index ede65c70..00000000 --- a/tests/typ/layout/hide.typ +++ /dev/null @@ -1,76 +0,0 @@ -// Test the `hide` function. - ---- -AB #h(1fr) CD \ -#hide[A]B #h(1fr) C#hide[D] ---- -Hidden: -#hide[#line(length: 100%)] -#line(length: 100%) ---- -Hidden: -#hide(table(rows: 2, columns: 2)[a][b][c][d]) -#table(rows: 2, columns: 2)[a][b][c][d] ---- -Hidden: -#hide[ - #polygon((20%, 0pt), - (60%, 0pt), - (80%, 2cm), - (0%, 2cm),) -] -#polygon((20%, 0pt), - (60%, 0pt), - (80%, 2cm), - (0%, 2cm),) ---- -#set rect( - inset: 8pt, - fill: rgb("e4e5ea"), - width: 100%, -) - -Hidden: -#hide[ -#grid( - columns: (1fr, 1fr, 2fr), - rows: (auto, 40pt), - gutter: 3pt, - rect[A], - rect[B], - rect[C], - rect(height: 100%)[D], -) -] -#grid( - columns: (1fr, 1fr, 2fr), - rows: (auto, 40pt), - gutter: 3pt, - rect[A], - rect[B], - rect[C], - rect(height: 100%)[D], -) ---- - -Hidden: -#hide[ -- 1 -- 2 - 1. A - 2. B -- 3 -] - - -- 1 -- 2 - 1. A - 2. B -- 3 - ---- -Hidden: -#hide(image("/assets/images/tiger.jpg", width: 5cm, height: 1cm,)) - -#image("/assets/images/tiger.jpg", width: 5cm, height: 1cm,) diff --git a/tests/typ/layout/list-attach.typ b/tests/typ/layout/list-attach.typ deleted file mode 100644 index 9d043eb0..00000000 --- a/tests/typ/layout/list-attach.typ +++ /dev/null @@ -1,54 +0,0 @@ -// Test list attaching. - ---- -// Test basic attached list. -Attached to: -- the bottom -- of the paragraph - -Next paragraph. - ---- -// Test that attached list isn't affected by block spacing. -#show list: set block(above: 100pt) -Hello -- A -World -- B - ---- -// Test non-attached list followed by attached list, -// separated by only word. -Hello - -- A - -World -- B - ---- -// Test non-attached tight list. -#set block(spacing: 15pt) -Hello -- A -World - -- B -- C - -More. - ---- -// Test that wide lists cannot be ... -#set block(spacing: 15pt) -Hello -- A - -- B -World - ---- -// ... even if forced to. -Hello -#list(tight: false)[A][B] -World diff --git a/tests/typ/layout/list-marker.typ b/tests/typ/layout/list-marker.typ deleted file mode 100644 index 9e28faad..00000000 --- a/tests/typ/layout/list-marker.typ +++ /dev/null @@ -1,34 +0,0 @@ -// Test list marker configuration. - ---- -// Test en-dash. -#set list(marker: [--]) -- A -- B - ---- -// Test that items are cycled. -#set list(marker: ([--], [•])) -- A - - B - - C - ---- -// Test function. -#set list(marker: n => if n == 1 [--] else [•]) -- A -- B - - C - - D - - E -- F - ---- -// Test that bare hyphen doesn't lead to cycles and crashes. -#set list(marker: [-]) -- Bare hyphen is -- a bad marker - ---- -// Error: 19-21 array must contain at least one marker -#set list(marker: ()) diff --git a/tests/typ/layout/list.typ b/tests/typ/layout/list.typ deleted file mode 100644 index 7b938944..00000000 --- a/tests/typ/layout/list.typ +++ /dev/null @@ -1,57 +0,0 @@ -// Test bullet lists. - ---- -_Shopping list_ -#list[Apples][Potatoes][Juice] - ---- -- First level. - - - Second level. - There are multiple paragraphs. - - - Third level. - - Still the same bullet point. - - - Still level 2. - -- At the top. - ---- -- Level 1 - - Level #[ -2 through content block -] - ---- - - Top-level indent -- is fine. - ---- - - A - - B - - C -- D - ---- -// This works because tabs are used consistently. - - A with 1 tab - - B with 2 tabs - ---- -// This doesn't work because of mixed tabs and spaces. - - A with 2 spaces - - B with 2 tabs - ---- -// Edge cases. -- -Not in list --Nope - ---- -// Alignment shouldn't affect marker -#set align(horizon) - -- ABCDEF\ GHIJKL\ MNOPQR diff --git a/tests/typ/layout/out-of-flow-in-block.typ b/tests/typ/layout/out-of-flow-in-block.typ deleted file mode 100644 index 2461aa5d..00000000 --- a/tests/typ/layout/out-of-flow-in-block.typ +++ /dev/null @@ -1,61 +0,0 @@ -// Test out-of-flow items (place, counter updates, etc.) at the -// beginning of a block not creating a frame just for them. - ---- -// No item in the first region. -#set page(height: 5cm, margin: 1cm) -No item in the first region. -#block(breakable: true, stroke: 1pt, inset: 0.5cm)[ - #rect(height: 2cm, fill: gray) -] - ---- -// Counter update in the first region. -#set page(height: 5cm, margin: 1cm) -Counter update. -#block(breakable: true, stroke: 1pt, inset: 0.5cm)[ - #counter("dummy").step() - #rect(height: 2cm, fill: gray) -] - ---- -// Placed item in the first region. -#set page(height: 5cm, margin: 1cm) -Placed item in the first region. -#block(breakable: true, above: 1cm, stroke: 1pt, inset: 0.5cm)[ - #place(dx: -0.5cm, dy: -0.75cm, box(width: 200%)[OOF]) - #rect(height: 2cm, fill: gray) -] - ---- -// In-flow item with size zero in the first region. -#set page(height: 5cm, margin: 1cm) -In-flow, zero-sized item. -#block(breakable: true, stroke: 1pt, inset: 0.5cm)[ - #set block(spacing: 0pt) - #line(length: 0pt) - #rect(height: 2cm, fill: gray) - #line(length: 100%) -] - ---- -// Counter update and placed item in the first region. -#set page(height: 5cm, margin: 1cm) -Counter update + place. -#block(breakable: true, above: 1cm, stroke: 1pt, inset: 0.5cm)[ - #counter("dummy").step() - #place(dx: -0.5cm, dy: -0.75cm, box([OOF])) - #rect(height: 2cm, fill: gray) -] - ---- -// Mix-and-match all the previous ones. -#set page(height: 5cm, margin: 1cm) -Mix-and-match all the previous tests. -#block(breakable: true, above: 1cm, stroke: 1pt, inset: 0.5cm)[ - #counter("dummy").step() - #place(dx: -0.5cm, dy: -0.75cm, box(width: 200%)[OOF]) - #line(length: 100%) - #place(dy: -0.8em)[OOF] - #rect(height: 2cm, fill: gray) -] diff --git a/tests/typ/layout/pad.typ b/tests/typ/layout/pad.typ deleted file mode 100644 index 0eff5876..00000000 --- a/tests/typ/layout/pad.typ +++ /dev/null @@ -1,30 +0,0 @@ -// Test the `pad` function. - ---- -// Use for indentation. -#pad(left: 10pt, [Indented!]) - -// All sides together. -#set rect(inset: 0pt) -#rect(fill: conifer, - pad(10pt, right: 20pt, - rect(width: 20pt, height: 20pt, fill: rgb("eb5278")) - ) -) - -Hi #box(pad(left: 10pt)[A]) there - ---- -// Pad can grow. -#pad(left: 10pt, right: 10pt)[PL #h(1fr) PR] - ---- -// Test that the pad element doesn't consume the whole region. -#set page(height: 6cm) -#align(left)[Before] -#pad(10pt, image("/assets/images/tiger.jpg")) -#align(right)[After] - ---- -// Test that padding adding up to 100% does not panic. -#pad(50%)[] diff --git a/tests/typ/layout/page-binding.typ b/tests/typ/layout/page-binding.typ deleted file mode 100644 index 66c8a3c6..00000000 --- a/tests/typ/layout/page-binding.typ +++ /dev/null @@ -1,46 +0,0 @@ -// Tests multi-page document with binding. - ---- -#set page(height: 100pt, margin: (inside: 30pt, outside: 20pt)) -#set par(justify: true) -#set text(size: 8pt) - -#page(margin: (x: 20pt), { - set align(center + horizon) - text(20pt, strong[Title]) - v(2em, weak: true) - text(15pt)[Author] -}) - -= Introduction -#lorem(35) - ---- -// Test setting the binding explicitly. -#set page(margin: (inside: 30pt)) -#rect(width: 100%)[Bound] -#pagebreak() -#rect(width: 100%)[Left] - ---- -// Test setting the binding explicitly. -#set page(binding: right, margin: (inside: 30pt)) -#rect(width: 100%)[Bound] -#pagebreak() -#rect(width: 100%)[Right] - ---- -// Test setting the binding implicitly. -#set page(margin: (inside: 30pt)) -#set text(lang: "he") -#rect(width: 100%)[Bound] -#pagebreak() -#rect(width: 100%)[Right] - ---- -// Error: 19-44 `inside` and `outside` are mutually exclusive with `left` and `right` -#set page(margin: (left: 1cm, outside: 2cm)) - ---- -// Error: 20-23 must be `left` or `right` -#set page(binding: top) diff --git a/tests/typ/layout/page-margin.typ b/tests/typ/layout/page-margin.typ deleted file mode 100644 index 00f2ed8a..00000000 --- a/tests/typ/layout/page-margin.typ +++ /dev/null @@ -1,20 +0,0 @@ -// Test page margins. - ---- -// Set all margins at once. -#[ - #set page(height: 20pt, margin: 5pt) - #place(top + left)[TL] - #place(bottom + right)[BR] -] - ---- -// Set individual margins. -#set page(height: 40pt) -#[#set page(margin: (left: 0pt)); #align(left)[Left]] -#[#set page(margin: (right: 0pt)); #align(right)[Right]] -#[#set page(margin: (top: 0pt)); #align(top)[Top]] -#[#set page(margin: (bottom: 0pt)); #align(bottom)[Bottom]] - -// Ensure that specific margins override general margins. -#[#set page(margin: (rest: 0pt, left: 20pt)); Overridden] diff --git a/tests/typ/layout/page-marginals.typ b/tests/typ/layout/page-marginals.typ deleted file mode 100644 index 589fb299..00000000 --- a/tests/typ/layout/page-marginals.typ +++ /dev/null @@ -1,24 +0,0 @@ -#set page( - paper: "a8", - margin: (x: 15pt, y: 30pt), - header: { - text(eastern)[*Typst*] - h(1fr) - text(0.8em)[_Chapter 1_] - }, - footer: context align(center)[\~ #counter(page).display() \~], - background: context if counter(page).get().first() <= 2 { - place(center + horizon, circle(radius: 1cm, fill: luma(90%))) - } -) - -But, soft! what light through yonder window breaks? It is the east, and Juliet -is the sun. Arise, fair sun, and kill the envious moon, Who is already sick and -pale with grief, That thou her maid art far more fair than she: Be not her maid, -since she is envious; Her vestal livery is but sick and green And none but fools -do wear it; cast it off. It is my lady, O, it is my love! O, that she knew she -were! She speaks yet she says nothing: what of that? Her eye discourses; I will -answer it. - -#set page(header: none, height: auto, margin: (top: 15pt, bottom: 25pt)) -The END. diff --git a/tests/typ/layout/page-number-align.typ b/tests/typ/layout/page-number-align.typ deleted file mode 100644 index 7559dd65..00000000 --- a/tests/typ/layout/page-number-align.typ +++ /dev/null @@ -1,25 +0,0 @@ -// Test page number alignment. - ---- -#set page( - height: 100pt, - margin: 30pt, - numbering: "(1)", - number-align: top + right, -) - -#block(width: 100%, height: 100%, fill: aqua.lighten(50%)) - ---- -#set page( - height: 100pt, - margin: 30pt, - numbering: "[1]", - number-align: bottom + left, -) - -#block(width: 100%, height: 100%, fill: aqua.lighten(50%)) - ---- -// Error: 25-39 expected `top` or `bottom`, found horizon -#set page(number-align: left + horizon) diff --git a/tests/typ/layout/page-style.typ b/tests/typ/layout/page-style.typ deleted file mode 100644 index 0d097554..00000000 --- a/tests/typ/layout/page-style.typ +++ /dev/null @@ -1,28 +0,0 @@ -// Test setting page styles. - ---- -// Empty with styles -// Should result in one conifer-colored A11 page. -#set page("a11", flipped: true, fill: conifer) - ---- -// Empty with styles and then pagebreak -// Should result in two forest-colored pages. -#set page(fill: forest) -#pagebreak() - ---- -// Empty with multiple page styles. -// Should result in a small white page. -#set page("a4") -#set page("a5") -#set page(width: 1cm, height: 1cm) - ---- -// Empty with multiple page styles. -// Should result in one eastern-colored A11 page. -#set page("a4") -#set page("a5") -#set page("a11", flipped: true, fill: eastern) -#set text(font: "Roboto", white) -#smallcaps[Typst] diff --git a/tests/typ/layout/page.typ b/tests/typ/layout/page.typ deleted file mode 100644 index f5c7822d..00000000 --- a/tests/typ/layout/page.typ +++ /dev/null @@ -1,42 +0,0 @@ -// Test the page class. - ---- -// Just empty page. -// Should result in auto-sized page, just like nothing. -#page[] - ---- -// Just empty page with styles. -// Should result in one conifer-colored A11 page. -#page("a11", flipped: true, fill: conifer)[] - ---- -// Set width and height. -// Should result in one high and one wide page. -#set page(width: 80pt, height: 80pt) -#[#set page(width: 40pt);High] -#[#set page(height: 40pt);Wide] - -// Flipped predefined paper. -#[#set page(paper: "a11", flipped: true);Flipped A11] - ---- -// Test page fill. -#set page(width: 80pt, height: 40pt, fill: eastern) -#text(15pt, font: "Roboto", fill: white, smallcaps[Typst]) -#page(width: 40pt, fill: none, margin: (top: 10pt, rest: auto))[Hi] - ---- -// Just page followed by pagebreak. -// Should result in one forest-colored A11 page and one auto-sized page. -#page("a11", flipped: true, fill: forest)[] -#pagebreak() - ---- -// Layout without any container should provide the page's dimensions, minus its margins. - -#page(width: 100pt, height: 100pt, { - layout(size => [This page has a width of #size.width and height of #size.height ]) - h(1em) - place(left, rect(width: 80pt, stroke: blue)) -}) diff --git a/tests/typ/layout/pagebreak-parity.typ b/tests/typ/layout/pagebreak-parity.typ deleted file mode 100644 index 4dbf723e..00000000 --- a/tests/typ/layout/pagebreak-parity.typ +++ /dev/null @@ -1,35 +0,0 @@ -// Test clearing to even or odd pages. - ---- -#set page(width: 80pt, height: 30pt) -First -#pagebreak(to: "odd") -Third -#pagebreak(to: "even") -Fourth -#pagebreak(to: "even") -Sixth -#pagebreak() -Seventh -#pagebreak(to: "odd") -#page[Ninth] - ---- -#set page(width: auto, height: auto) - -// Test with auto-sized page. -First -#pagebreak(to: "odd") -Third - ---- -#set page(height: 30pt, width: 80pt) - -// Test when content extends to more than one page -First - -Second - -#pagebreak(to: "odd") - -Third diff --git a/tests/typ/layout/pagebreak-weak.typ b/tests/typ/layout/pagebreak-weak.typ deleted file mode 100644 index c228959e..00000000 --- a/tests/typ/layout/pagebreak-weak.typ +++ /dev/null @@ -1,30 +0,0 @@ -// Test page breaks on basically empty pages. - ---- -// After place -// Should result in three pages. -First -#pagebreak(weak: true) -#place(right)[placed A] -#pagebreak(weak: true) -Third - ---- -// After only ignorables & invisibles -// Should result in two pages. -First -#pagebreak(weak: true) -#counter(page).update(1) -#metadata("Some") -#pagebreak(weak: true) -Second - ---- -// After only ignorables, but regular break -// Should result in three pages. -First -#pagebreak() -#counter(page).update(1) -#metadata("Some") -#pagebreak() -Third diff --git a/tests/typ/layout/pagebreak.typ b/tests/typ/layout/pagebreak.typ deleted file mode 100644 index f5921191..00000000 --- a/tests/typ/layout/pagebreak.typ +++ /dev/null @@ -1,45 +0,0 @@ -// Test forced page breaks. - ---- -// Just a pagebreak. -// Should result in two pages. -#pagebreak() - ---- -// Pagebreak, empty with styles and then pagebreak -// Should result in one auto-sized page and two conifer-colored 2cm wide pages. -#pagebreak() -#set page(width: 2cm, fill: conifer) -#pagebreak() - ---- -// Two text bodies separated with and surrounded by weak pagebreaks. -// Should result in two aqua-colored pages. -#set page(fill: aqua) -#pagebreak(weak: true) -First -#pagebreak(weak: true) -Second -#pagebreak(weak: true) - ---- -// Test a combination of pagebreaks, styled pages and pages with bodies. -// Should result in three five pages, with the fourth one being forest-colored. -#set page(width: 80pt, height: 30pt) -#[#set page(width: 60pt); First] -#pagebreak() -#pagebreak() -Third -#page(height: 20pt, fill: forest)[] -Fif#[#set page();th] - ---- -// Test hard and weak pagebreak followed by page with body. -// Should result in three navy-colored pages. -#set page(fill: navy) -#set text(fill: white) -First -#pagebreak() -#page[Second] -#pagebreak(weak: true) -#page[Third] diff --git a/tests/typ/layout/par-bidi.typ b/tests/typ/layout/par-bidi.typ deleted file mode 100644 index 4ff83802..00000000 --- a/tests/typ/layout/par-bidi.typ +++ /dev/null @@ -1,72 +0,0 @@ -// Test bidirectional text and language configuration. - ---- -// Test reordering with different top-level paragraph directions. -#let content = par[Text טֶקסט] -#text(lang: "he", content) -#text(lang: "de", content) - ---- -// Test that consecutive, embedded LTR runs stay LTR. -// Here, we have two runs: "A" and italic "B". -#let content = par[أنت A#emph[B]مطرC] -#set text(font: ("PT Sans", "Noto Sans Arabic")) -#text(lang: "ar", content) -#text(lang: "de", content) - ---- -// Test that consecutive, embedded RTL runs stay RTL. -// Here, we have three runs: "גֶ", bold "שֶׁ", and "ם". -#let content = par[Aגֶ#strong[שֶׁ]םB] -#set text(font: ("Linux Libertine", "Noto Serif Hebrew")) -#text(lang: "he", content) -#text(lang: "de", content) - ---- -// Test embedding up to level 4 with isolates. -#set text(dir: rtl) -א\u{2066}A\u{2067}Bב\u{2069}? - ---- -// Test hard line break (leads to two paragraphs in unicode-bidi). -#set text(lang: "ar", font: ("Noto Sans Arabic", "PT Sans")) -Life المطر هو الحياة \ -الحياة تمطر is rain. - ---- -// Test spacing. -L #h(1cm) ריווחR \ -Lריווח #h(1cm) R - ---- -// Test inline object. -#set text(lang: "he") -קרנפיםRh#box(image("/assets/images/rhino.png", height: 11pt))inoחיים - ---- -// Test whether L1 whitespace resetting destroys stuff. -الغالب #h(70pt) ن#" "ة - ---- -// Test explicit dir -#set text(dir: rtl) -#text("8:00 - 9:00",dir:ltr) בבוקר -#linebreak() -ב #text("12:00 - 13:00",dir:ltr) בצהריים - ---- -// Mixing raw -#set text(lang: "he") -לדוג. `if a == b:` זה תנאי -#set raw(lang:"python") -לדוג. `if a == b:` זה תנאי - -#show raw: set text(dir:rtl) -לתכנת בעברית `אם א == ב:` - ---- -// Test setting a vertical direction. -// Ref: false - -// Error: 16-19 text direction must be horizontal -#set text(dir: ttb) diff --git a/tests/typ/layout/par-indent.typ b/tests/typ/layout/par-indent.typ deleted file mode 100644 index e807d74d..00000000 --- a/tests/typ/layout/par-indent.typ +++ /dev/null @@ -1,51 +0,0 @@ -// Test paragraph indent. - ---- -#set par(first-line-indent: 12pt, leading: 5pt) -#set block(spacing: 5pt) -#show heading: set text(size: 10pt) - -The first paragraph has no indent. - -But the second one does. - -#box(image("/assets/images/tiger.jpg", height: 6pt)) -starts a paragraph, also with indent. - -#align(center, image("/assets/images/rhino.png", width: 1cm)) - -= Headings -- And lists. -- Have no indent. - - Except if you have another paragraph in them. - -#set text(8pt, lang: "ar", font: ("Noto Sans Arabic", "Linux Libertine")) -#set par(leading: 8pt) - -= Arabic -دع النص يمطر عليك - -ثم يصبح النص رطبًا وقابل للطرق ويبدو المستند رائعًا. - ---- -// This is madness. -#set par(first-line-indent: 12pt) -Why would anybody ever ... - -... want spacing and indent? - ---- -// Test hanging indent. -#set par(hanging-indent: 15pt, justify: true) -#lorem(10) - ---- -#set par(hanging-indent: 1em) -Welcome \ here. Does this work well? - ---- -#set par(hanging-indent: 2em) -#set text(dir: rtl) -لآن وقد أظلم الليل وبدأت النجوم -تنضخ وجه الطبيعة التي أعْيَتْ من طول ما انبعثت في النهار diff --git a/tests/typ/layout/par-justify-cjk.typ b/tests/typ/layout/par-justify-cjk.typ deleted file mode 100644 index d0fef644..00000000 --- a/tests/typ/layout/par-justify-cjk.typ +++ /dev/null @@ -1,64 +0,0 @@ -// Test Chinese text in narrow lines. - -// In Chinese typography, line length should be multiples of the character size -// and the line ends should be aligned with each other. -// Most Chinese publications do not use hanging punctuation at line end. -#set page(width: auto) -#set par(justify: true) -#set text(lang: "zh", font: "Noto Serif CJK SC") - -#rect(inset: 0pt, width: 80pt, fill: rgb("eee"))[ - 中文维基百科使用汉字书写,汉字是汉族或华人的共同文字,是中国大陆、新加坡、马来西亚、台湾、香港、澳门的唯一官方文字或官方文字之一。25.9%,而美国和荷兰则分別占13.7%及8.2%。近年來,中国大陆地区的维基百科编辑者正在迅速增加; -] - ---- -// Japanese typography is more complex, make sure it is at least a bit sensible. -#set page(width: auto) -#set par(justify: true) -#set text(lang: "ja", font: ("Linux Libertine", "Noto Serif CJK JP")) -#rect(inset: 0pt, width: 80pt, fill: rgb("eee"))[ - ウィキペディア(英: Wikipedia)は、世界中のボランティアの共同作業によって執筆及び作成されるフリーの多言語インターネット百科事典である。主に寄付に依って活動している非営利団体「ウィキメディア財団」が所有・運営している。 - - 専門家によるオンライン百科事典プロジェクトNupedia(ヌーペディア)を前身として、2001年1月、ラリー・サンガーとジミー・ウェールズ(英: Jimmy Donal "Jimbo" Wales)により英語でプロジェクトが開始された。 -] - ---- -// Test punctuation whitespace adjustment -#set page(width: auto) -#set text(lang: "zh", font: "Noto Serif CJK SC") -#set par(justify: true) -#rect(inset: 0pt, width: 80pt, fill: rgb("eee"))[ - “引号测试”,还, - - 《书名》《测试》下一行 - - 《书名》《测试》。 -] - -「『引号』」。“‘引号’”。 - ---- -// Test Variants of Mainland China, Hong Kong, and Japan. - -// 17 characters a line. -#set page(width: 170pt + 10pt, margin: (x: 5pt)) -#set text(lang: "zh", font: "Noto Serif CJK SC") -#set par(justify: true) - -孔雀最早见于《山海经》中的《海内经》:“有孔雀。”东汉杨孚著《异物志》记载,岭南:“孔雀,其大如大雁而足高,毛皆有斑纹彩,捕而蓄之,拍手即舞。” - -#set text(lang: "zh", region: "hk", font: "Noto Serif CJK TC") -孔雀最早见于《山海经》中的《海内经》:「有孔雀。」东汉杨孚著《异物志》记载,岭南:「孔雀,其大如大雁而足高,毛皆有斑纹彩,捕而蓄之,拍手即舞。」 - ---- -// Test punctuation marks adjustment in justified paragraph. - -// The test case includes the following scenarios: -// - Compression of punctuation marks at line start or line end -// - Adjustment of adjacent punctuation marks - -#set page(width: 110pt + 10pt, margin: (x: 5pt)) -#set text(lang: "zh", font: "Noto Serif CJK SC") -#set par(justify: true) - -标注在字间的标点符号(乙式括号省略号以外)通常占一个汉字宽度,使其易于识别、适合配置及排版,有些排版风格完全不对标点宽度进行任何调整。但是为了让文字体裁更加紧凑易读,,,以及执行3.1.4 行首行尾禁则时,就需要对标点符号的宽度进行调整。是否调整取决于…… diff --git a/tests/typ/layout/par-justify.typ b/tests/typ/layout/par-justify.typ deleted file mode 100644 index 69576c7d..00000000 --- a/tests/typ/layout/par-justify.typ +++ /dev/null @@ -1,65 +0,0 @@ - ---- -#set page(width: 180pt) -#set block(spacing: 5pt) -#set par(justify: true, first-line-indent: 14pt, leading: 5pt) - -This text is justified, meaning that spaces are stretched so that the text -forms a "block" with flush edges at both sides. - -First line indents and hyphenation play nicely with justified text. - ---- -// Test that lines with hard breaks aren't justified. -#set par(justify: true) -A B C \ -D - ---- -// Test forced justification with justified break. -A B C #linebreak(justify: true) -D E F #linebreak(justify: true) - ---- -// Test that there are no hick-ups with justification enabled and -// basically empty paragraph. -#set par(justify: true) -#"" - ---- -// Test that the last line can be shrunk -#set page(width: 155pt) -#set par(justify: true) -This text can be fitted in one line. - ---- -// Test that runts are avoided when it's not too costly to do so. -#set page(width: 124pt) -#set par(justify: true) -#for i in range(0, 20) { - "a b c " -} -#"d" - ---- -// Test that justification cannot lead to a leading space -#set par(justify: true) -#set text(size: 12pt) -#set page(width: 45mm, height: auto) - -lorem ipsum 1234, lorem ipsum dolor sit amet - -#" leading whitespace should still be displayed" - ---- -// Test that justification doesn't break code blocks - -#set par(justify: true) - -```cpp -int main() { - printf("Hello world\n"); - return 0; -} -``` - diff --git a/tests/typ/layout/par-knuth.typ b/tests/typ/layout/par-knuth.typ deleted file mode 100644 index 50f9280a..00000000 --- a/tests/typ/layout/par-knuth.typ +++ /dev/null @@ -1,30 +0,0 @@ -#set page(width: auto, height: auto) -#set par(leading: 4pt, justify: true) -#set text(font: "New Computer Modern") - -#let story = [ - In olden times when wishing still helped one, there lived a king whose - daughters were all beautiful; and the youngest was so beautiful that the sun - itself, which has seen so much, was astonished whenever it shone in her face. - Close by the king’s castle lay a great dark forest, and under an old lime-tree - in the forest was a well, and when the day was very warm, the king’s child - went out into the forest and sat down by the side of the cool fountain; and - when she was bored she took a golden ball, and threw it up on high and caught - it; and this ball was her favorite plaything. -] - -#let column(title, linebreaks, hyphenate) = { - rect(inset: 0pt, width: 132pt, fill: rgb("eee"))[ - #set par(linebreaks: linebreaks) - #set text(hyphenate: hyphenate) - #strong(title) \ #story - ] -} - -#grid( - columns: 3, - gutter: 10pt, - column([Simple without hyphens], "simple", false), - column([Simple with hyphens], "simple", true), - column([Optimized with hyphens], "optimized", true), -) diff --git a/tests/typ/layout/par-simple.typ b/tests/typ/layout/par-simple.typ deleted file mode 100644 index 34a2d626..00000000 --- a/tests/typ/layout/par-simple.typ +++ /dev/null @@ -1,20 +0,0 @@ -// Test plain text. - ---- -#set page(width: 250pt, height: 120pt) - -But, soft! what light through yonder window breaks? It is the east, and Juliet -is the sun. Arise, fair sun, and kill the envious moon, Who is already sick and -pale with grief, That thou her maid art far more fair than she: Be not her maid, -since she is envious; Her vestal livery is but sick and green And none but fools -do wear it; cast it off. It is my lady, O, it is my love! O, that she knew she -were! She speaks yet she says nothing: what of that? Her eye discourses; I will -answer it. - -I am too bold, 'tis not to me she speaks: Two of the fairest stars in all the -heaven, Having some business, do entreat her eyes To twinkle in their spheres -till they return. What if her eyes were there, they in her head? The brightness -of her cheek would shame those stars, As daylight doth a lamp; her eyes in -heaven Would through the airy region stream so bright That birds would sing and -think it were not night. See, how she leans her cheek upon her hand! O, that I -were a glove upon that hand, That I might touch that cheek! diff --git a/tests/typ/layout/par.typ b/tests/typ/layout/par.typ deleted file mode 100644 index 45b60cf5..00000000 --- a/tests/typ/layout/par.typ +++ /dev/null @@ -1,36 +0,0 @@ -// Test configuring paragraph properties. - ---- -// Test ragged-left. -#set align(right) -To the right! Where the sunlight peeks behind the mountain. - ---- -// Test changing leading and spacing. -#set block(spacing: 1em) -#set par(leading: 2pt) -But, soft! what light through yonder window breaks? - -It is the east, and Juliet is the sun. - ---- -// Test that paragraph spacing loses against block spacing. -// TODO -#set block(spacing: 100pt) -#show table: set block(above: 5pt, below: 5pt) -Hello -#table(columns: 4, fill: (x, y) => if calc.odd(x + y) { silver })[A][B][C][D] - ---- -// While we're at it, test the larger block spacing wins. -#set block(spacing: 0pt) -#show raw: set block(spacing: 15pt) -#show list: set block(spacing: 2.5pt) - -```rust -fn main() {} -``` - -- List - -Paragraph diff --git a/tests/typ/layout/place-background.typ b/tests/typ/layout/place-background.typ deleted file mode 100644 index afee0622..00000000 --- a/tests/typ/layout/place-background.typ +++ /dev/null @@ -1,18 +0,0 @@ -// Test placing a background image on a page. - ---- -#set page(paper: "a10", flipped: true) -#set text(fill: white) -#place( - dx: -10pt, - dy: -10pt, - image( - "/assets/images/tiger.jpg", - fit: "cover", - width: 100% + 20pt, - height: 100% + 20pt, - ) -) -#align(bottom + right)[ - _Welcome to_ #underline[*Tigerland*] -] diff --git a/tests/typ/layout/place-float-auto.typ b/tests/typ/layout/place-float-auto.typ deleted file mode 100644 index 2ca3dc3a..00000000 --- a/tests/typ/layout/place-float-auto.typ +++ /dev/null @@ -1,31 +0,0 @@ -// Test floating placement. - ---- -#set page(height: 140pt) -#set place(clearance: 5pt) -#lorem(6) -#place(auto, float: true, rect[A]) -#place(auto, float: true, rect[B]) -#place(auto, float: true, rect[C]) -#place(auto, float: true, rect[D]) - ---- -// Error: 2-20 automatic positioning is only available for floating placement -// Hint: 2-20 you can enable floating placement with `place(float: true, ..)` -#place(auto)[Hello] - ---- -// Error: 2-45 floating placement must be `auto`, `top`, or `bottom` -#place(center + horizon, float: true)[Hello] - ---- -// Error: 2-36 floating placement must be `auto`, `top`, or `bottom` -#place(horizon, float: true)[Hello] - ---- -// Error: 2-27 floating placement must be `auto`, `top`, or `bottom` -#place(float: true)[Hello] - ---- -// Error: 2-34 floating placement must be `auto`, `top`, or `bottom` -#place(right, float: true)[Hello] diff --git a/tests/typ/layout/place-float-columns.typ b/tests/typ/layout/place-float-columns.typ deleted file mode 100644 index e2b88d46..00000000 --- a/tests/typ/layout/place-float-columns.typ +++ /dev/null @@ -1,19 +0,0 @@ -// Test floats in columns. - ---- -#set page(height: 200pt, width: 300pt) -#show: columns.with(2) - -= Introduction -#figure( - placement: bottom, - caption: [A glacier], - image("/assets/images/glacier.jpg", width: 50%), -) -#lorem(45) -#figure( - placement: top, - caption: [A rectangle], - rect[Hello!], -) -#lorem(20) diff --git a/tests/typ/layout/place-float-figure.typ b/tests/typ/layout/place-float-figure.typ deleted file mode 100644 index 4d76fd8f..00000000 --- a/tests/typ/layout/place-float-figure.typ +++ /dev/null @@ -1,21 +0,0 @@ -// Test floating figures. - ---- -#set page(height: 250pt, width: 150pt) - -= Introduction -#lorem(10) #footnote[Lots of Latin] - -#figure( - placement: bottom, - caption: [A glacier #footnote[Lots of Ice]], - image("/assets/images/glacier.jpg", width: 80%), -) - -#lorem(40) - -#figure( - placement: top, - caption: [An important], - image("/assets/images/diagram.svg", width: 80%), -) diff --git a/tests/typ/layout/place-nested.typ b/tests/typ/layout/place-nested.typ deleted file mode 100644 index 93006ff5..00000000 --- a/tests/typ/layout/place-nested.typ +++ /dev/null @@ -1,40 +0,0 @@ -// Test vertical alignment with nested placement. - ---- -#box( - fill: aqua, - width: 30pt, - height: 30pt, - place(bottom, - place(line(start: (0pt, 0pt), end: (20pt, 0pt), stroke: red + 3pt)) - ) -) - ---- -#box( - fill: aqua, - width: 30pt, - height: 30pt, - { - box(fill: yellow, { - [Hello] - place(horizon, line(start: (0pt, 0pt), end: (20pt, 0pt), stroke: red + 2pt)) - }) - place(horizon, line(start: (0pt, 0pt), end: (20pt, 0pt), stroke: green + 3pt)) - } -) - ---- -#box(fill: aqua)[ - #place(bottom + right)[Hi] - Hello World \ - How are \ - you? -] - ---- -#box(fill: aqua)[ - #place(top + left, dx: 50%, dy: 50%)[Hi] - #v(30pt) - #line(length: 50pt) -] diff --git a/tests/typ/layout/place.typ b/tests/typ/layout/place.typ deleted file mode 100644 index d426e07f..00000000 --- a/tests/typ/layout/place.typ +++ /dev/null @@ -1,35 +0,0 @@ -// Test the `place` function. - ---- -#set page("a8") -#place(bottom + center)[© Typst] - -= Placement -#place(right, image("/assets/images/tiger.jpg", width: 1.8cm)) -Hi there. This is \ -a placed element. \ -Unfortunately, \ -the line breaks still had to be inserted manually. - -#stack( - rect(fill: eastern, height: 10pt, width: 100%), - place(right, dy: 1.5pt)[ABC], - rect(fill: conifer, height: 10pt, width: 80%), - rect(fill: forest, height: 10pt, width: 100%), - 10pt, - block[ - #place(center, dx: -7pt, dy: -5pt)[Hello] - #place(center, dx: 7pt, dy: 5pt)[Hello] - Hello #h(1fr) Hello - ] -) - ---- -// Test how the placed element interacts with paragraph spacing around it. -#set page("a8", height: 60pt) - -First - -#place(bottom + right)[Placed] - -Second diff --git a/tests/typ/layout/repeat.typ b/tests/typ/layout/repeat.typ deleted file mode 100644 index 173f9d57..00000000 --- a/tests/typ/layout/repeat.typ +++ /dev/null @@ -1,44 +0,0 @@ -// Test the `repeat` function. - ---- -// Test multiple repeats. -#let sections = ( - ("Introduction", 1), - ("Approach", 1), - ("Evaluation", 3), - ("Discussion", 15), - ("Related Work", 16), - ("Conclusion", 253), -) - -#for section in sections [ - #section.at(0) #box(width: 1fr, repeat[.]) #section.at(1) \ -] - ---- -// Test dots with RTL. -#set text(lang: "ar") -مقدمة #box(width: 1fr, repeat[.]) 15 - ---- -// Test empty repeat. -A #box(width: 1fr, repeat[]) B - ---- -// Test unboxed repeat. -#repeat(rect(width: 2em, height: 1em)) - ---- -// Test single repeat in both directions. -A#box(width: 1fr, repeat(rect(width: 6em, height: 0.7em)))B - -#set align(center) -A#box(width: 1fr, repeat(rect(width: 6em, height: 0.7em)))B - -#set text(dir: rtl) -ريجين#box(width: 1fr, repeat(rect(width: 4em, height: 0.7em)))سون - ---- -// Error: 2:2-2:13 repeat with no size restrictions -#set page(width: auto) -#repeat(".") diff --git a/tests/typ/layout/spacing.typ b/tests/typ/layout/spacing.typ deleted file mode 100644 index faba60b4..00000000 --- a/tests/typ/layout/spacing.typ +++ /dev/null @@ -1,46 +0,0 @@ -// Test the `h` and `v` functions. - ---- -// Linebreak and leading-sized weak spacing are equivalent. -#box[A \ B] #box[A #v(0.65em, weak: true) B] - -// Eating up soft spacing. -Inv#h(0pt)isible - -// Multiple spacings in a row. -Add #h(10pt) #h(10pt) up - -// Relative to area. -#let x = 25% - 4pt -|#h(x)|#h(x)|#h(x)|#h(x)| - -// Fractional. -| #h(1fr) | #h(2fr) | #h(1fr) | - ---- -// Test spacing collapsing before spacing. -#set align(right) -A #h(0pt) B #h(0pt) \ -A B \ -A #h(-1fr) B - ---- -// Test spacing collapsing with different font sizes. -#grid(columns: 2)[ - #text(size: 12pt, block(below: 1em)[A]) - #text(size: 8pt, block(above: 1em)[B]) -][ - #text(size: 12pt, block(below: 1em)[A]) - #text(size: 8pt, block(above: 1.25em)[B]) -] - ---- -// Test RTL spacing. -#set text(dir: rtl) -A #h(10pt) B \ -A #h(1fr) B - ---- -// Missing spacing. -// Error: 10-13 missing argument: amount -Totally #h() ignored diff --git a/tests/typ/layout/stack-1.typ b/tests/typ/layout/stack-1.typ deleted file mode 100644 index 8b5472e8..00000000 --- a/tests/typ/layout/stack-1.typ +++ /dev/null @@ -1,52 +0,0 @@ -// Test stack layouts. - ---- -// Test stacks with different directions. -#let widths = ( - 30pt, 20pt, 40pt, 15pt, - 30pt, 50%, 20pt, 100%, -) - -#let shaded(i, w) = { - let v = (i + 1) * 10% - rect(width: w, height: 10pt, fill: rgb(v, v, v)) -} - -#let items = for (i, w) in widths.enumerate() { - (align(right, shaded(i, w)),) -} - -#set page(width: 50pt, margin: 0pt) -#stack(dir: btt, ..items) - ---- -// Test spacing. -#set page(width: 50pt, margin: 0pt) - -#let x = square(size: 10pt, fill: eastern) -#stack( - spacing: 5pt, - stack(dir: rtl, spacing: 5pt, x, x, x), - stack(dir: ltr, x, 20%, x, 20%, x), - stack(dir: ltr, spacing: 5pt, x, x, 7pt, 3pt, x), -) - ---- -// Test overflow. -#set page(width: 50pt, height: 30pt, margin: 0pt) -#box(stack( - rect(width: 40pt, height: 20pt, fill: conifer), - rect(width: 30pt, height: 13pt, fill: forest), -)) - ---- -// Test aligning things in RTL stack with align function & fr units. -#set page(width: 50pt, margin: 5pt) -#set block(spacing: 5pt) -#set text(8pt) -#stack(dir: rtl, 1fr, [A], 1fr, [B], [C]) -#stack(dir: rtl, - align(center, [A]), - align(left, [B]), - [C], -) diff --git a/tests/typ/layout/stack-2.typ b/tests/typ/layout/stack-2.typ deleted file mode 100644 index a06950f1..00000000 --- a/tests/typ/layout/stack-2.typ +++ /dev/null @@ -1,23 +0,0 @@ -// Test fr units in stacks. - ---- -#set page(height: 3.5cm) -#stack( - dir: ltr, - spacing: 1fr, - ..for c in "ABCDEFGHI" {([#c],)} -) - -Hello -#v(2fr) -from #h(1fr) the #h(1fr) wonderful -#v(1fr) -World! 🌍 - ---- -#set page(height: 2cm) -#set text(white) -#rect(fill: forest)[ - #v(1fr) - #h(1fr) Hi you! -] diff --git a/tests/typ/layout/table-cell.typ b/tests/typ/layout/table-cell.typ deleted file mode 100644 index cbe0b9f0..00000000 --- a/tests/typ/layout/table-cell.typ +++ /dev/null @@ -1,128 +0,0 @@ -// Test basic styling using the table.cell element. - ---- -// Cell override -#table( - align: left, - fill: red, - stroke: blue, - columns: 2, - [AAAAA], [BBBBB], - [A], [B], - table.cell(align: right)[C], [D], - align(right)[E], [F], - align(horizon)[G], [A\ A\ A], - table.cell(align: horizon)[G2], [A\ A\ A], - table.cell(inset: 0pt)[I], [F], - [H], table.cell(fill: blue)[J] -) - ---- -// Cell show rule -#show table.cell: it => [Zz] - -#table( - align: left, - fill: red, - stroke: blue, - columns: 2, - [AAAAA], [BBBBB], - [A], [B], - table.cell(align: right)[C], [D], - align(right)[E], [F], - align(horizon)[G], [A\ A\ A] -) - ---- -#show table.cell: it => (it.align, it.fill) -#table( - align: left, - row-gutter: 5pt, - [A], - table.cell(align: right)[B], - table.cell(fill: aqua)[B], -) - ---- -// Cell set rules -#set table.cell(align: center) -#show table.cell: it => (it.align, it.fill, it.inset) -#set table.cell(inset: 20pt) -#table( - align: left, - row-gutter: 5pt, - [A], - table.cell(align: right)[B], - table.cell(fill: aqua)[B], -) - ---- -// Test folding per-cell properties (align and inset) -#table( - columns: (1fr, 1fr), - rows: (2.5em, auto), - align: right, - fill: (x, y) => (green, aqua).at(calc.rem(x + y, 2)), - [Top], table.cell(align: bottom)[Bot], - table.cell(inset: (bottom: 0pt))[Bot], table.cell(inset: (bottom: 0pt))[Bot] -) - ---- -// Test overriding outside alignment -#set align(bottom + right) -#table( - columns: (1fr, 1fr), - rows: 2em, - align: auto, - fill: green, - [BR], [BR], - table.cell(align: left, fill: aqua)[BL], table.cell(align: top, fill: red.lighten(50%))[TR] -) - ---- -// First doc example -#table( - columns: 2, - fill: green, - align: right, - [*Name*], [*Data*], - table.cell(fill: blue)[J.], [Organizer], - table.cell(align: center)[K.], [Leader], - [M.], table.cell(inset: 0pt)[Player] -) - ---- -#{ - show table.cell: emph - table( - columns: 2, - [Person], [Animal], - [John], [Dog] - ) -} - ---- -// Style based on position -#{ - show table.cell: it => { - if it.y == 0 { - strong(it) - } else if it.x == 1 { - emph(it) - } else { - it - } - } - table( - columns: 3, - gutter: 3pt, - [Name], [Age], [Info], - [John], [52], [Nice], - [Mary], [50], [Cool], - [Jake], [49], [Epic] - ) -} - ---- -// Error: 8-19 cannot use `grid.cell` as a table cell; use `table.cell` instead -#table(grid.cell[]) diff --git a/tests/typ/layout/table.typ b/tests/typ/layout/table.typ deleted file mode 100644 index 89a7dab5..00000000 --- a/tests/typ/layout/table.typ +++ /dev/null @@ -1,141 +0,0 @@ -// Test tables. - ---- -#set page(height: 70pt) -#set table(fill: (x, y) => if calc.even(x + y) { rgb("aaa") }) - -#table( - columns: (1fr,) * 3, - stroke: 2pt + rgb("333"), - [A], [B], [C], [], [], [D \ E \ F \ \ \ G], [H], -) - ---- -#table(columns: 3, stroke: none, fill: green, [A], [B], [C]) - ---- -// Test alignment with array. -#table( - columns: (1fr, 1fr, 1fr), - align: (left, center, right), - [A], [B], [C] -) - -// Test empty array. -#set align(center) -#table( - columns: (1fr, 1fr, 1fr), - align: (), - [A], [B], [C] -) - ---- -// Test inset. -#table( - columns: 3, - inset: 10pt, - [A], [B], [C] -) - -#table( - columns: 3, - inset: (y: 10pt), - [A], [B], [C] -) - -#table( - columns: 3, - inset: (left: 20pt, rest: 10pt), - [A], [B], [C] -) - -#table( - columns: 2, - inset: ( - left: 20pt, - right: 5pt, - top: 10pt, - bottom: 3pt, - ), - [A], - [B], -) - -#table( - columns: 3, - fill: (x, y) => (if y == 0 { aqua } else { orange }).darken(x * 15%), - inset: (x, y) => (left: if x == 0 { 0pt } else { 5pt }, right: if x == 0 { 5pt } else { 0pt }, y: if y == 0 { 0pt } else { 5pt }), - [A], [B], [C], - [A], [B], [C], -) - -#table( - columns: 3, - inset: (0pt, 5pt, 10pt), - fill: (x, _) => aqua.darken(x * 15%), - [A], [B], [C], -) - ---- -// Test inset folding -#set table(inset: 10pt) -#set table(inset: (left: 0pt)) - -#table( - fill: red, - inset: (right: 0pt), - table.cell(inset: (top: 0pt))[a] -) - ---- -// Test interaction with gutters. -#table( - columns: (3em, 3em), - fill: (x, y) => (red, blue).at(calc.rem(x, 2)), - align: (x, y) => (left, right).at(calc.rem(y, 2)), - [A], [B], - [C], [D], - [E], [F], - [G], [H] -) - -#table( - columns: (3em, 3em), - fill: (x, y) => (red, blue).at(calc.rem(x, 2)), - align: (x, y) => (left, right).at(calc.rem(y, 2)), - row-gutter: 5pt, - [A], [B], - [C], [D], - [E], [F], - [G], [H] -) - -#table( - columns: (3em, 3em), - fill: (x, y) => (red, blue).at(calc.rem(x, 2)), - align: (x, y) => (left, right).at(calc.rem(y, 2)), - column-gutter: 5pt, - [A], [B], - [C], [D], - [E], [F], - [G], [H] -) - -#table( - columns: (3em, 3em), - fill: (x, y) => (red, blue).at(calc.rem(x, 2)), - align: (x, y) => (left, right).at(calc.rem(y, 2)), - gutter: 5pt, - [A], [B], - [C], [D], - [E], [F], - [G], [H] -) - ---- -// Ref: false -#table() - ---- -// Error: 14-19 expected color, gradient, pattern, none, array, or function, found string -#table(fill: "hey") diff --git a/tests/typ/layout/terms.typ b/tests/typ/layout/terms.typ deleted file mode 100644 index 178aa98b..00000000 --- a/tests/typ/layout/terms.typ +++ /dev/null @@ -1,60 +0,0 @@ -// Test term list. - ---- -// Test with constructor. -#terms( - ([One], [First]), - ([Two], [Second]), -) - ---- -// Test joining. -#for word in lorem(4).split().map(s => s.trim(".")) [ - / #word: Latin stuff. -] - ---- -// Test multiline. -#set text(8pt) - -/ Fruit: A tasty, edible thing. -/ Veggie: - An important energy source - for vegetarians. - - And healthy! - ---- -// Test style change. -#set text(8pt) -/ First list: #lorem(6) - -#set terms(hanging-indent: 30pt) -/ Second list: #lorem(5) - ---- -// Test RTL. -#set text(8pt, dir: rtl) - -/ פרי: דבר טעים, אכיל. ומקור אנרגיה חשוב לצמחונים. - ---- -// Test grid like show rule. -#show terms: it => table( - columns: 2, - inset: 3pt, - ..it.children.map(v => (emph(v.term), v.description)).flatten(), -) - -/ A: One letter -/ BB: Two letters -/ CCC: Three letters - ---- -/ Term: -Not in list -/Nope - ---- -// Error: 8 expected colon -/ Hello diff --git a/tests/typ/layout/transform-layout.typ b/tests/typ/layout/transform-layout.typ deleted file mode 100644 index ce6dc930..00000000 --- a/tests/typ/layout/transform-layout.typ +++ /dev/null @@ -1,58 +0,0 @@ -// Test layout transformations - ---- -// Test that rotation impact layout. -#set page(width: 200pt) -#set rotate(reflow: true) - -#let one(angle) = box(fill: aqua, rotate(angle)[Test Text]) -#for angle in range(0, 360, step: 15) { - one(angle * 1deg) -} - ---- -// Test relative sizing in rotated boxes. -#set page(width: 200pt, height: 200pt) -#set text(size: 32pt) -#let rotated(body) = box(rotate( - 90deg, - box(stroke: 0.5pt, height: 20%, clip: true, body) -)) - -#set rotate(reflow: false) -Hello #rotated[World]!\ - -#set rotate(reflow: true) -Hello #rotated[World]! - ---- -// Test that scaling impact layout. -#set page(width: 200pt) -#set text(size: 32pt) -#let scaled(body) = box(scale( - x: 20%, - y: 40%, - body -)) - -#set scale(reflow: false) -Hello #scaled[World]! - -#set scale(reflow: true) -Hello #scaled[World]! - ---- -// Test relative sizing in scaled boxes. -#set page(width: 200pt, height: 200pt) -#set text(size: 32pt) -#let scaled(body) = box(scale( - x: 60%, - y: 40%, - box(stroke: 0.5pt, width: 30%, clip: true, body) -)) - -#set scale(reflow: false) -Hello #scaled[World]!\ - -#set scale(reflow: true) -Hello #scaled[World]! diff --git a/tests/typ/layout/transform.typ b/tests/typ/layout/transform.typ deleted file mode 100644 index f74ec2b0..00000000 --- a/tests/typ/layout/transform.typ +++ /dev/null @@ -1,49 +0,0 @@ -// Test transformations. - ---- -// Test creating the TeX and XeTeX logos. -#let size = 11pt -#let tex = { - [T] - h(-0.14 * size) - box(move(dy: 0.22 * size)[E]) - h(-0.12 * size) - [X] -} - -#let xetex = { - [X] - h(-0.14 * size) - box(scale(x: -100%, move(dy: 0.26 * size)[E])) - h(-0.14 * size) - [T] - h(-0.14 * size) - box(move(dy: 0.26 * size)[E]) - h(-0.12 * size) - [X] -} - -#set text(font: "New Computer Modern", size) -Neither #tex, \ -nor #xetex! - ---- -// Test combination of scaling and rotation. -#set page(height: 80pt) -#align(center + horizon, - rotate(20deg, scale(70%, image("/assets/images/tiger.jpg"))) -) - ---- -// Test setting rotation origin. -#rotate(10deg, origin: top + left, - image("/assets/images/tiger.jpg", width: 50%) -) - ---- -// Test setting scaling origin. -#let r = rect(width: 100pt, height: 10pt, fill: forest) -#set page(height: 65pt) -#box(scale(r, x: 50%, y: 200%, origin: left + top)) -#box(scale(r, x: 50%, origin: center)) -#box(scale(r, x: 50%, y: 200%, origin: right + bottom)) diff --git a/tests/typ/lint/markup.typ b/tests/typ/lint/markup.typ deleted file mode 100644 index 319fec11..00000000 --- a/tests/typ/lint/markup.typ +++ /dev/null @@ -1,26 +0,0 @@ -/// Test markup lints. -// Ref: false - ---- -// Warning: 1-3 no text within stars -// Hint: 1-3 using multiple consecutive stars (e.g. **) has no additional effect -** - ---- -// Warning: 1-3 no text within stars -// Hint: 1-3 using multiple consecutive stars (e.g. **) has no additional effect -// Warning: 11-13 no text within stars -// Hint: 11-13 using multiple consecutive stars (e.g. **) has no additional effect -**not bold** - ---- -// Warning: 1-3 no text within underscores -// Hint: 1-3 using multiple consecutive underscores (e.g. __) has no additional effect -__ - ---- -// Warning: 1-3 no text within underscores -// Hint: 1-3 using multiple consecutive underscores (e.g. __) has no additional effect -// Warning: 13-15 no text within underscores -// Hint: 13-15 using multiple consecutive underscores (e.g. __) has no additional effect -__not italic__ diff --git a/tests/typ/math/accent.typ b/tests/typ/math/accent.typ deleted file mode 100644 index 315e14b3..00000000 --- a/tests/typ/math/accent.typ +++ /dev/null @@ -1,33 +0,0 @@ -// Test math accents. - ---- -// Test function call. -$grave(a), acute(b), hat(f), tilde(§), macron(ä), diaer(a), ä \ - breve(\&), dot(!), circle(a), caron(@), arrow(Z), arrow.l(Z)$ - ---- -$ x &= p \ dot(x) &= v \ dot.double(x) &= a \ dot.triple(x) &= j \ dot.quad(x) &= s $ - ---- -// Test `accent` function. -$accent(ö, .), accent(v, <-), accent(ZZ, \u{0303})$ - ---- -// Test accent bounds. -$sqrt(tilde(T)) + hat(f)/hat(g)$ - ---- -// Test wide base. -$arrow("ABC" + d), tilde(sum)$ - ---- -// Test effect of accent on superscript. -$A^x != hat(A)^x != hat(hat(A))^x$ - ---- -// Test high base. -$ tilde(integral), tilde(integral)_a^b, tilde(integral_a^b) $ - ---- -// Test accent size. -$tilde(sum), tilde(sum, size: #50%), accent(H, hat, size: #200%)$ diff --git a/tests/typ/math/alignment.typ b/tests/typ/math/alignment.typ deleted file mode 100644 index 177e0188..00000000 --- a/tests/typ/math/alignment.typ +++ /dev/null @@ -1,34 +0,0 @@ -// Test implicit alignment math. - ---- -// Test alignment step functions. -#set page(width: 225pt) -$ -"a" &= c \ -&= c + 1 & "By definition" \ -&= d + 100 + 1000 \ -&= x && "Even longer" \ -$ - ---- -// Test post-fix alignment. -$ -& "right" \ -"a very long line" \ -"left" \ -$ - ---- -// Test no alignment. -$ -"right" \ -"a very long line" \ -"left" \ -$ - ---- -// Test #460 equations. -$ -a &=b & quad c&=d \ -e &=f & g&=h -$ diff --git a/tests/typ/math/attach-p1.typ b/tests/typ/math/attach-p1.typ deleted file mode 100644 index 5564ec60..00000000 --- a/tests/typ/math/attach-p1.typ +++ /dev/null @@ -1,63 +0,0 @@ -// Test t and b attachments, part 1. - ---- -// Test basics, postscripts. -$f_x + t^b + V_1^2 + attach(A, t: alpha, b: beta)$ - ---- -// Test basics, prescripts. Notably, the upper and lower prescripts' content need to be -// aligned on the right edge of their bounding boxes, not on the left as in postscripts. -$ -attach(upright(O), bl: 8, tl: 16, br: 2, tr: 2-), -attach("Pb", bl: 82, tl: 207) + attach(upright(e), bl: -1, tl: 0) + macron(v)_e \ -$ - ---- -// A mixture of attachment positioning schemes. -$ -attach(a, tl: u), attach(a, tr: v), attach(a, bl: x), -attach(a, br: y), limits(a)^t, limits(a)_b \ - -attach(a, tr: v, t: t), -attach(a, tr: v, br: y), -attach(a, br: y, b: b), -attach(limits(a), b: b, bl: x), -attach(a, tl: u, bl: x), -attach(limits(a), t: t, tl: u) \ - -attach(a, tl: u, tr: v), -attach(limits(a), t: t, br: y), -attach(limits(a), b: b, tr: v), -attach(a, bl: x, br: y), -attach(limits(a), b: b, tl: u), -attach(limits(a), t: t, bl: u), -limits(a)^t_b \ - -attach(a, tl: u, tr: v, bl: x, br: y), -attach(limits(a), t: t, bl: x, br: y, b: b), -attach(limits(a), t: t, tl: u, tr: v, b: b), -attach(limits(a), tl: u, bl: x, t: t, b: b), -attach(limits(a), t: t, b: b, tr: v, br: y), -attach(a, tl: u, t: t, tr: v, bl: x, b: b, br: y) -$ - ---- -// Test function call after subscript. -$pi_1(Y), a_f(x), a^zeta (x), a^abs(b)_sqrt(c) \ - a^subset.eq (x), a_(zeta(x)), pi_(1(Y)), a^(abs(b))_(sqrt(c))$ - ---- -// Test associativity and scaling. -$ 1/(V^2^3^4^5), - frac( - attach( - limits(V), br: attach(2, br: 3), b: attach(limits(2), b: 3)), - attach( - limits(V), tl: attach(2, tl: 3), t: attach(limits(2), t: 3))), - attach(Omega, - tl: attach(2, tl: attach(3, tl: attach(4, tl: 5))), - tr: attach(2, tr: attach(3, tr: attach(4, tr: 5))), - bl: attach(2, bl: attach(3, bl: attach(4, bl: 5))), - br: attach(2, br: attach(3, br: attach(4, br: 5))), - ) -$ diff --git a/tests/typ/math/attach-p2.typ b/tests/typ/math/attach-p2.typ deleted file mode 100644 index 8f97f74f..00000000 --- a/tests/typ/math/attach-p2.typ +++ /dev/null @@ -1,27 +0,0 @@ -// Test t and b attachments, part 2. - ---- -// Test high subscript and superscript. -$ sqrt(a_(1/2)^zeta), sqrt(a_alpha^(1/2)), sqrt(a_(1/2)^(3/4)) \ - sqrt(attach(a, tl: 1/2, bl: 3/4)), - sqrt(attach(a, tl: 1/2, bl: 3/4, tr: 1/2, br: 3/4)) $ - ---- -// Test for no collisions between descenders/ascenders and attachments - -$ sup_(x in P_i) quad inf_(x in P_i) $ -$ op("fff",limits: #true)^(y) quad op("yyy", limits:#true)_(f) $ - ---- -// Test frame base. -$ (-1)^n + (1/2 + 3)^(-1/2) $ - ---- -#set text(size: 8pt) - -// Test that the attachments are aligned horizontally. -$ x_1 p_1 frak(p)_1 2_1 dot_1 lg_1 !_1 \\_1 ]_1 "ip"_1 op("iq")_1 \ - x^1 b^1 frak(b)^1 2^1 dot^1 lg^1 !^1 \\^1 ]^1 "ib"^1 op("id")^1 \ - x_1 y_1 "_"_1 x^1 l^1 "`"^1 attach(I,tl:1,bl:1,tr:1,br:1) - scripts(sum)_1^1 integral_1^1 abs(1/2)_1^1 \ - x^1_1, "("b y")"^1_1 != (b y)^1_1, "[∫]"_1 [integral]_1 $ diff --git a/tests/typ/math/attach-p3.typ b/tests/typ/math/attach-p3.typ deleted file mode 100644 index 3591c248..00000000 --- a/tests/typ/math/attach-p3.typ +++ /dev/null @@ -1,42 +0,0 @@ -// Test t and b attachments, part 3. - ---- -// Test limit. -$ lim_(n->oo \ n "grows") sum_(k=0 \ k in NN)^n k $ - ---- -// Test forcing scripts and limits. -$ limits(A)_1^2 != A_1^2 $ -$ scripts(sum)_1^2 != sum_1^2 $ -$ limits(integral)_a^b != integral_a^b $ - ---- -// Error: 25-29 unknown variable: oops -$ attach(A, t: #context oops) $ - ---- -// Show and let rules for limits and scripts -#let eq = $ ∫_a^b iota_a^b $ -#eq -#show "∫": math.limits -#show math.iota: math.limits.with(inline: false) -#eq -$iota_a^b$ - ---- -// Test default of limit attachments on relations at all sizes -#set page(width: auto) -$ a =^"def" b quad a lt.eq_"really" b quad a arrow.r.long.squiggly^"slowly" b $ -$a =^"def" b quad a lt.eq_"really" b quad a arrow.r.long.squiggly^"slowly" b$ - -$a scripts(=)^"def" b quad a scripts(lt.eq)_"really" b quad a scripts(arrow.r.long.squiggly)^"slowly" b$ - ---- -// Test default of scripts attachments on integrals at display size -$ integral.sect_a^b quad \u{2a1b}_a^b quad limits(\u{2a1b})_a^b $ -$integral.sect_a^b quad \u{2a1b}_a^b quad limits(\u{2a1b})_a^b$ - ---- -// Test default of limit attachments on large operators at display size only -$ tack.t.big_0^1 quad \u{02A0A}_0^1 quad join_0^1 $ -$tack.t.big_0^1 quad \u{02A0A}_0^1 quad join_0^1$ diff --git a/tests/typ/math/call.typ b/tests/typ/math/call.typ deleted file mode 100644 index 0fce1627..00000000 --- a/tests/typ/math/call.typ +++ /dev/null @@ -1,7 +0,0 @@ -// Test function calls that aren't typst functions - ---- -$ pi(a) $ -$ pi(a,) $ -$ pi(a,b) $ -$ pi(a,b,) $ diff --git a/tests/typ/math/cancel.typ b/tests/typ/math/cancel.typ deleted file mode 100644 index ac715154..00000000 --- a/tests/typ/math/cancel.typ +++ /dev/null @@ -1,38 +0,0 @@ -// Tests the cancel() function. - ---- -// Inline -$a + 5 + cancel(x) + b - cancel(x)$ - -$c + (a dot.c cancel(b dot.c c))/(cancel(b dot.c c))$ - ---- -// Display -#set page(width: auto) -$ a + b + cancel(b + c) - cancel(b) - cancel(c) - 5 + cancel(6) - cancel(6) $ -$ e + (a dot.c cancel((b + c + d)))/(cancel(b + c + d)) $ - ---- -// Inverted -$a + cancel(x, inverted: #true) - cancel(x, inverted: #true) + 10 + cancel(y) - cancel(y)$ -$ x + cancel("abcdefg", inverted: #true) $ - ---- -// Cross -$a + cancel(b + c + d, cross: #true, stroke: #red) + e$ -$ a + cancel(b + c + d, cross: #true) + e $ - ---- -// Resized and styled -#set page(width: 200pt, height: auto) -$a + cancel(x, length: #200%) - cancel(x, length: #50%, stroke: #(red + 1.1pt))$ -$ b + cancel(x, length: #150%) - cancel(a + b + c, length: #50%, stroke: #(blue + 1.2pt)) $ - ---- -// Specifying cancel line angle with an absolute angle -$cancel(x, angle: #0deg) + cancel(x, angle: #45deg) + cancel(x, angle: #90deg) + cancel(x, angle: #135deg)$ - ---- -// Specifying cancel line angle with a function -$x + cancel(y, angle: #{angle => angle + 90deg}) - cancel(z, angle: #(angle => angle + 135deg))$ -$ e + cancel((j + e)/(f + e)) - cancel((j + e)/(f + e), angle: #(angle => angle + 30deg)) $ diff --git a/tests/typ/math/cases.typ b/tests/typ/math/cases.typ deleted file mode 100644 index d591ae50..00000000 --- a/tests/typ/math/cases.typ +++ /dev/null @@ -1,9 +0,0 @@ -// Test case distinction. - ---- -$ f(x, y) := cases( - 1 quad &"if" (x dot y)/2 <= 0, - 2 &"if" x divides 2, - 3 &"if" x in NN, - 4 &"else", -) $ diff --git a/tests/typ/math/class.typ b/tests/typ/math/class.typ deleted file mode 100644 index a5901b31..00000000 --- a/tests/typ/math/class.typ +++ /dev/null @@ -1,47 +0,0 @@ -// Test math classes. - ---- -// Test characters. -$ a class("normal", +) b \ - a class("binary", .) b \ - lr(class("opening", \/) a/b class("closing", \\)) \ - { x class("fence", \;) x > 0} \ - a class("large", \/) b \ - a class("punctuation", :) b \ - a class("relation", ~) b \ - a + class("unary", times) b \ - class("vary", :) a class("vary", :) b $ - ---- -// Test custom content. -#let dotsq = square( - size: 0.7em, - stroke: 0.5pt, - align(center+horizon, circle(radius: 0.15em, fill: black)) -) - -$ a dotsq b \ - a class("normal", dotsq) b \ - a class("vary", dotsq) b \ - a + class("vary", dotsq) b \ - a class("punctuation", dotsq) b $ - ---- -// Test nested. -#let normal = math.class.with("normal") -#let pluseq = $class("binary", normal(+) normal(=))$ -$ a pluseq 5 $ - ---- -// Test exceptions. -$ sqrt(3)\/2 quad d_0.d_1d_2 dots $ - ---- -// Test if the math class changes the limit configuration. -$ class("normal", ->)_a $ -$class("relation", x)_a$ -$ class("large", x)_a $ -$class("large", ->)_a$ - -$limits(class("normal", ->))_a$ -$ scripts(class("relation", x))_a $ diff --git a/tests/typ/math/content.typ b/tests/typ/math/content.typ deleted file mode 100644 index 739377ae..00000000 --- a/tests/typ/math/content.typ +++ /dev/null @@ -1,33 +0,0 @@ -// Test arbitrary content in math. - ---- -// Test images and font fallback. -#let monkey = move(dy: 0.2em, image("/assets/images/monkey.svg", height: 1em)) -$ sum_(i=#emoji.apple)^#emoji.apple.red i + monkey/2 $ - ---- -// Test tables. -$ x := #table(columns: 2)[x][y]/mat(1, 2, 3) - = #table[A][B][C] $ ---- -// Test non-equation math directly in content. -#math.attach($a$, t: [b]) - ---- -// Test font switch. -#let here = text.with(font: "Noto Sans") -$#here[f] := #here[Hi there]$. - ---- -// Test boxes without a baseline act as if the baseline is at the base -#{ - box(stroke: 0.2pt, $a #box(stroke: 0.2pt, $a$)$) - h(12pt) - box(stroke: 0.2pt, $a #box(stroke: 0.2pt, $g$)$) - h(12pt) - box(stroke: 0.2pt, $g #box(stroke: 0.2pt, $g$)$) -} - ---- -// Test boxes with a baseline are respected -#box(stroke: 0.2pt, $a #box(baseline:0.5em, stroke: 0.2pt, $a$)$) diff --git a/tests/typ/math/delimited.typ b/tests/typ/math/delimited.typ deleted file mode 100644 index 8500aec2..00000000 --- a/tests/typ/math/delimited.typ +++ /dev/null @@ -1,59 +0,0 @@ -// Test delimiter matching and scaling. - ---- -// Test automatic matching. -#set page(width:122pt) -$ (a) + {b/2} + abs(a)/2 + (b) $ -$f(x/2) < zeta(c^2 + abs(a + b/2))$ - ---- -// Test unmatched. -$[1,2[ = [1,2) != zeta\(x/2\) $ - ---- -// Test manual matching. -$ [|a/b|] != lr(|]a/b|]) != [a/b) $ -$ lr(| ]1,2\[ + 1/2|) $ - ---- -// Test fence confusion. -$ |x + |y| + z/a| \ - lr(|x + |y| + z/a|) $ - ---- -// Test that symbols aren't matched automatically. -$ bracket.l a/b bracket.r - = lr(bracket.l a/b bracket.r) $ - ---- -// Test half LRs. -$ lr(a/b\]) = a = lr(\{a/b) $ - ---- -// Test manual scaling. -$ lr(]sum_(x=1)^n x], size: #70%) - < lr((1, 2), size: #200%) $ - ---- -// Test predefined delimiter pairings. -$floor(x/2), ceil(x/2), abs(x), norm(x)$ - ---- -// Test colored delimiters -$ lr( - text("(", fill: #green) a/b - text(")", fill: #blue) - ) $ - ---- -// Test middle functions -$ { x mid(|) sum_(i=1)^oo phi_i (x) < 1 } \ - { integral |x| dif x - mid(bar.v.double) - floor(hat(A) mid(|) { x mid(|) y } mid(|) A) } $ - ---- -// Test ignoring weak spacing immediately after the opening -// and immediately before the closing. - -$ [#h(1em, weak: true)A(dif x, f(x) dif x)sum#h(1em, weak: true)] $ diff --git a/tests/typ/math/equation-block-align.typ b/tests/typ/math/equation-block-align.typ deleted file mode 100644 index c6c9cd89..00000000 --- a/tests/typ/math/equation-block-align.typ +++ /dev/null @@ -1,33 +0,0 @@ -// Test alignment of block equations. - ---- -// Test unnumbered -#let eq(alignment) = { - show math.equation: set align(alignment) - $ a + b = c $ -} - -#eq(center) -#eq(left) -#eq(right) - -#set text(dir: rtl) -#eq(start) -#eq(end) - ---- -// Test numbered -#let eq(alignment) = { - show math.equation: set align(alignment) - $ a + b = c $ -} - -#set math.equation(numbering: "(1)") - -#eq(center) -#eq(left) -#eq(right) - -#set text(dir: rtl) -#eq(start) -#eq(end) diff --git a/tests/typ/math/equation-number.typ b/tests/typ/math/equation-number.typ deleted file mode 100644 index 3de611b3..00000000 --- a/tests/typ/math/equation-number.typ +++ /dev/null @@ -1,145 +0,0 @@ -// Test equation number, and its interaction with equation -// block's alignment and text direction. - ---- -#set math.equation(numbering: "(1)") - -$ a + b = c $ - -#show math.equation: set align(center) -$ a + b = c $ -#show math.equation: set align(left) -$ a + b = c $ -#show math.equation: set align(right) -$ a + b = c $ - -#set text(dir: rtl) -#show math.equation: set align(start) -$ a + b = c $ -#show math.equation: set align(end) -$ a + b = c $ - ---- -#set math.equation(numbering: "(1)", number-align: start) - -$ a + b = c $ - -#show math.equation: set align(center) -$ a + b = c $ -#show math.equation: set align(left) -$ a + b = c $ -#show math.equation: set align(right) -$ a + b = c $ - -#set text(dir: rtl) -#show math.equation: set align(start) -$ a + b = c $ -#show math.equation: set align(end) -$ a + b = c $ - ---- -#set math.equation(numbering: "(1)", number-align: end) - -$ a + b = c $ - -#show math.equation: set align(center) -$ a + b = c $ -#show math.equation: set align(left) -$ a + b = c $ -#show math.equation: set align(right) -$ a + b = c $ - -#set text(dir: rtl) -#show math.equation: set align(start) -$ a + b = c $ -#show math.equation: set align(end) -$ a + b = c $ - ---- -#set math.equation(numbering: "(1)", number-align: left) - -$ a + b = c $ - -#show math.equation: set align(center) -$ a + b = c $ -#show math.equation: set align(left) -$ a + b = c $ -#show math.equation: set align(right) -$ a + b = c $ - -#set text(dir: rtl) -#show math.equation: set align(start) -$ a + b = c $ -#show math.equation: set align(end) -$ a + b = c $ - ---- -#set math.equation(numbering: "(1)", number-align: right) - -$ a + b = c $ - -#show math.equation: set align(center) -$ a + b = c $ -#show math.equation: set align(left) -$ a + b = c $ -#show math.equation: set align(right) -$ a + b = c $ - -#set text(dir: rtl) -#show math.equation: set align(start) -$ a + b = c $ -#show math.equation: set align(end) -$ a + b = c $ - ---- -// Error: 52-58 expected `start`, `left`, `right`, or `end`, found center -#set math.equation(numbering: "(1)", number-align: center) - ---- -// Error: 52-67 expected `start`, `left`, `right`, or `end`, found center -#set math.equation(numbering: "(1)", number-align: center + bottom) - ---- -#set math.equation(numbering: "(1)") - -$ p &= ln a b \ - &= ln a + ln b $ - ---- -#set math.equation(numbering: "(1)", number-align: top+start) - -$ p &= ln a b \ - &= ln a + ln b $ - ---- -#show math.equation: set align(left) -#set math.equation(numbering: "(1)", number-align: bottom) - -$ q &= ln sqrt(a b) \ - &= 1/2 (ln a + ln b) $ - ---- -// Tests that if the numbering's layout box vertically exceeds the box of -// the equation frame's boundary, the latter's frame is resized correctly -// to encompass the numbering. #box() below delineates the resized frame. -// -// A row with "-" only has a height that's smaller than the height of the -// numbering's layout box. Note we use pattern "1" here, not "(1)", since -// the parenthesis exceeds the numbering's layout box, due to the default -// settings of top-edge and bottom-edge of the TextElem that laid it out. -#set math.equation(numbering: "1", number-align: top) -#box( -$ - &- - \ - a &= b $, -fill: silver) - -#set math.equation(numbering: "1", number-align: horizon) -#box( -$ - - - $, -fill: silver) - -#set math.equation(numbering: "1", number-align: bottom) -#box( -$ a &= b \ - - &- - $, -fill: silver) diff --git a/tests/typ/math/equation-show.typ b/tests/typ/math/equation-show.typ deleted file mode 100644 index 9334c54e..00000000 --- a/tests/typ/math/equation-show.typ +++ /dev/null @@ -1,7 +0,0 @@ -// Test show rules on equations. - ---- -This is small: $sum_(i=0)^n$ - -#show math.equation: math.display -This is big: $sum_(i=0)^n$ diff --git a/tests/typ/math/font-features.typ b/tests/typ/math/font-features.typ deleted file mode 100644 index ffdd1924..00000000 --- a/tests/typ/math/font-features.typ +++ /dev/null @@ -1,10 +0,0 @@ -// Test that setting font features in math.equation has an effect. - ---- -$ nothing $ -$ "hi ∅ hey" $ -$ sum_(i in NN) 1 + i $ -#show math.equation: set text(features: ("cv01",), fallback: false) -$ nothing $ -$ "hi ∅ hey" $ -$ sum_(i in NN) 1 + i $ diff --git a/tests/typ/math/frac.typ b/tests/typ/math/frac.typ deleted file mode 100644 index fc7dd14b..00000000 --- a/tests/typ/math/frac.typ +++ /dev/null @@ -1,43 +0,0 @@ -// Test fractions. - ---- -// Test that denominator baseline matches in the common case. -$ x = 1/2 = a/(a h) = a/a = a/(1/2) $ - ---- -// Test parenthesis removal. -$ (|x| + |y|)/2 < [1+2]/3 $ - ---- -// Test large fraction. -$ x = (-b plus.minus sqrt(b^2 - 4a c))/(2a) $ - ---- -// Test binomial. -$ binom(circle, square) $ - ---- -// Test multinomial coefficients. -$ binom(n, k_1, k_2, k_3) $ - ---- -// Error: 3-13 missing argument: lower -$ binom(x^2) $ - ---- -// Test dif. -$ (dif y)/(dif x), dif/x, x/dif, dif/dif \ - frac(dif y, dif x), frac(dif, x), frac(x, dif), frac(dif, dif) $ - ---- -// Test associativity. -$ 1/2/3 = (1/2)/3 = 1/(2/3) $ - ---- -// Test precedence. -$ a_1/b_2, 1/f(x), zeta(x)/2, "foo"[|x|]/2 \ - 1.2/3.7, 2.3^3.4 \ - 🏳️🌈[x]/2, f [x]/2, phi [x]/2, 🏳️🌈 [x]/2 \ - +[x]/2, 1(x)/2, 2[x]/2 \ - (a)b/2, b(a)[b]/2 \ - n!/2, 5!/2, n !/2, 1/n!, 1/5! $ diff --git a/tests/typ/math/linebreak.typ b/tests/typ/math/linebreak.typ deleted file mode 100644 index 88ce69d2..00000000 --- a/tests/typ/math/linebreak.typ +++ /dev/null @@ -1,50 +0,0 @@ -// Test inline equation line breaking. - ---- -// Basic breaking after binop, rel -#let hrule(x) = box(line(length: x)) -#hrule(45pt)$e^(pi i)+1 = 0$\ -#hrule(55pt)$e^(pi i)+1 = 0$\ -#hrule(70pt)$e^(pi i)+1 = 0$ - ---- -// LR groups prevent linbreaking. -#let hrule(x) = box(line(length: x)) -#hrule(76pt)$a+b$\ -#hrule(74pt)$(a+b)$\ -#hrule(74pt)$paren.l a+b paren.r$ - ---- -// Multiline yet inline does not linebreak -#let hrule(x) = box(line(length: x)) -#hrule(80pt)$a + b \ c + d$\ - ---- -// A single linebreak at the end still counts as one line. -#let hrule(x) = box(line(length: x)) -#hrule(60pt)$e^(pi i)+1 = 0\ $ - ---- -// Inline, in a box, doesn't linebreak. -#let hrule(x) = box(line(length: x)) -#hrule(80pt)#box($a+b$) - ---- -// A relation followed by a relation doesn't linebreak -#let hrule(x) = box(line(length: x)) -#hrule(70pt)$a < = b$\ -#hrule(74pt)$a < = b$ - ---- -// Page breaks can happen after a relation even if there is no -// explicit space. -#let hrule(x) = box(line(length: x)) -#hrule(90pt)$<;$\ -#hrule(95pt)$<;$\ -#hrule(90pt)$<)$\ -#hrule(95pt)$<)$ - ---- -// Verify empty rows are handled ok. -$ $\ -Nothing: $ $, just empty. diff --git a/tests/typ/math/matrix-alignment.typ b/tests/typ/math/matrix-alignment.typ deleted file mode 100644 index 0b3aa456..00000000 --- a/tests/typ/math/matrix-alignment.typ +++ /dev/null @@ -1,58 +0,0 @@ -// Test matrix alignment math. - ---- -// Test alternating alignment in a vector. -$ vec( - "a" & "a a a" & "a a", - "a a" & "a a" & "a", - "a a a" & "a" & "a a a", -) $ - ---- -// Test alternating explicit alignment in a matrix. -$ mat( - "a" & "a a a" & "a a"; - "a a" & "a a" & "a"; - "a a a" & "a" & "a a a"; -) $ - ---- -// Test alignment in a matrix. -$ mat( - "a", "a a a", "a a"; - "a a", "a a", "a"; - "a a a", "a", "a a a"; -) $ - ---- -// Test explicit left alignment in a matrix. -$ mat( - &"a", &"a a a", &"a a"; - &"a a", &"a a", &"a"; - &"a a a", &"a", &"a a a"; -) $ - ---- -// Test explicit right alignment in a matrix. -$ mat( - "a"&, "a a a"&, "a a"&; - "a a"&, "a a"&, "a"&; - "a a a"&, "a"&, "a a a"&; -) $ - ---- -// Test #460 equations. -#let stop = { - math.class("punctuation",$.$) -} -$ mat(&a+b,c;&d, e) $ -$ mat(&a+b&,c;&d&, e) $ -$ mat(&&&a+b,c;&&&d, e) $ -$ mat(stop &a+b&stop,c;...stop stop&d&...stop stop, e) $ - ---- -// Test #454 equations. -$ mat(-1, 1, 1; 1, -1, 1; 1, 1, -1) $ -$ mat(-1&, 1&, 1&; 1&, -1&, 1&; 1&, 1&, -1&) $ -$ mat(-1&, 1&, 1&; 1, -1, 1; 1, 1, -1) $ -$ mat(&-1, &1, &1; 1, -1, 1; 1, 1, -1) $ diff --git a/tests/typ/math/matrix-gaps.typ b/tests/typ/math/matrix-gaps.typ deleted file mode 100644 index ef33b518..00000000 --- a/tests/typ/math/matrix-gaps.typ +++ /dev/null @@ -1,17 +0,0 @@ -// Test matrices, cases and vec gaps - ---- -#set math.mat(row-gap: 1em, column-gap: 2em) -$ mat(1, 2; 3, 4) $ - ---- -#set math.mat(gap: 1em) -$ mat(1, 2; 3, 4) $ - ---- -#set math.cases(gap: 1em) -$ x = cases(1, 2) $ - ---- -#set math.vec(gap: 1em) -$ vec(1, 2) $ diff --git a/tests/typ/math/matrix.typ b/tests/typ/math/matrix.typ deleted file mode 100644 index 57ecd85f..00000000 --- a/tests/typ/math/matrix.typ +++ /dev/null @@ -1,97 +0,0 @@ -// Test matrices. - ---- -// Test semicolon syntax. -#set align(center) -$mat() dot - mat(;) dot - mat(1, 2) dot - mat(1, 2;) \ - mat(1; 2) dot - mat(1, 2; 3, 4) dot - mat(1 + &2, 1/2; &3, 4)$ - ---- -// Test sparse matrix. -$ mat( - 1, 2, ..., 10; - 2, 2, ..., 10; - dots.v, dots.v, dots.down, dots.v; - 10, 10, ..., 10; -) $ - ---- -// Test baseline alignment. -$ mat( - a, b^2; - sum_(x \ y) x, a^(1/2); - zeta, alpha; -) $ - ---- -// Test alternative delimiter with set rule. -#set math.mat(delim: "[") -$ mat(1, 2; 3, 4) $ -$ a + mat(delim: #none, 1, 2; 3, 4) + b $ - ---- -// Test alternative math delimiter directly in call. -#set align(center) -#grid( - columns: 3, - gutter: 10pt, - - $ mat(1, 2, delim: "[") $, - $ mat(1, 2; delim: "[") $, - $ mat(delim: "[", 1, 2) $, - - $ mat(1; 2; delim: "[") $, - $ mat(1; delim: "[", 2) $, - $ mat(delim: "[", 1; 2) $, - - $ mat(1, 2; delim: "[", 3, 4) $, - $ mat(delim: "[", 1, 2; 3, 4) $, - $ mat(1, 2; 3, 4; delim: "[") $, -) - ---- -// Error: 13-14 expected array, found content -$ mat(1, 2; 3, 4, delim: "[") $, - ---- -$ mat(B, A B) $ -$ mat(B, A B, dots) $ -$ mat(B, A B, dots;) $ -$ mat(#1, #(foo: "bar")) $ - ---- - -// Test matrix line drawing (augmentation). -#grid( - columns: 2, - gutter: 10pt, - - $ mat(10, 2, 3, 4; 5, 6, 7, 8; augment: #3) $, - $ mat(10, 2, 3, 4; 5, 6, 7, 8; augment: #(-1)) $, - $ mat(100, 2, 3; 4, 5, 6; 7, 8, 9; augment: #(hline: 2)) $, - $ mat(100, 2, 3; 4, 5, 6; 7, 8, 9; augment: #(hline: -1)) $, - $ mat(100, 2, 3; 4, 5, 6; 7, 8, 9; augment: #(hline: 1, vline: 1)) $, - $ mat(100, 2, 3; 4, 5, 6; 7, 8, 9; augment: #(hline: -2, vline: -2)) $, - $ mat(100, 2, 3; 4, 5, 6; 7, 8, 9; augment: #(vline: 2, stroke: 1pt + blue)) $, - $ mat(100, 2, 3; 4, 5, 6; 7, 8, 9; augment: #(vline: -1, stroke: 1pt + blue)) $, -) - ---- - -// Test using matrix line drawing with a set rule. -#set math.mat(augment: (hline: 2, vline: 1, stroke: 2pt + green)) -$ mat(1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 1) $ - -#set math.mat(augment: 2) -$ mat(1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 1) $ - -#set math.mat(augment: none) - ---- -// Error: 3-37 cannot draw a vertical line after column 3 of a matrix with 3 columns -$ mat(1, 0, 0; 0, 1, 1; augment: #3) $, diff --git a/tests/typ/math/multiline.typ b/tests/typ/math/multiline.typ deleted file mode 100644 index b1f43800..00000000 --- a/tests/typ/math/multiline.typ +++ /dev/null @@ -1,56 +0,0 @@ -// Test multiline math. - ---- -// Test basic alignment. -$ x &= x + y \ - &= x + 2z \ - &= sum x dot 2z $ - ---- -// Test text before first alignment point. -$ x + 1 &= a^2 + b^2 \ - y &= a + b^2 \ - z &= alpha dot beta $ - ---- -// Test space between inner alignment points. -$ a + b &= 2 + 3 &= 5 \ - b &= c &= 3 $ - ---- -// Test in case distinction. -$ f := cases( - 1 + 2 &"iff" &x, - 3 &"if" &y, -) $ - ---- -// Test mixing lines with and some without alignment points. -$ "abc" &= c \ - &= d + 1 \ - = x $ - ---- -// Test multiline subscript. -$ sum_(n in NN \ n <= 5) n = (5(5+1))/2 = 15 $ - ---- -// Test no trailing line break. -$ -"abc" &= c -$ -No trailing line break. - ---- -// Test single trailing line break. -$ -"abc" &= c \ -$ -One trailing line break. - ---- -// Test multiple trailing line breaks. -$ -"abc" &= c \ \ \ -$ -Multiple trailing line breaks. diff --git a/tests/typ/math/numbering.typ b/tests/typ/math/numbering.typ deleted file mode 100644 index fd303ff2..00000000 --- a/tests/typ/math/numbering.typ +++ /dev/null @@ -1,11 +0,0 @@ -// Test equation numbering. - ---- -#set page(width: 150pt) -#set math.equation(numbering: "(I)") - -We define $x$ in preparation of @fib: -$ phi.alt := (1 + sqrt(5)) / 2 $ <ratio> - -With @ratio, we get -$ F_n = round(1 / sqrt(5) phi.alt^n) $ <fib> diff --git a/tests/typ/math/op.typ b/tests/typ/math/op.typ deleted file mode 100644 index 14e1c6e6..00000000 --- a/tests/typ/math/op.typ +++ /dev/null @@ -1,30 +0,0 @@ -// Test text operators. - ---- -// Test predefined. -$ max_(1<=n<=m) n $ - ---- -// With or without parens. -$ &sin x + log_2 x \ - = &sin(x) + log_2(x) $ - ---- -// Test scripts vs limits. -#set page(width: auto) -#set text(font: "New Computer Modern") -Discuss $lim_(n->oo) 1/n$ now. -$ lim_(n->infinity) 1/n = 0 $ - ---- -// Test custom operator. -$ op("myop", limits: #false)_(x:=1) x \ - op("myop", limits: #true)_(x:=1) x $ - ---- -// Test styled operator. -$ bold(op("bold", limits: #true))_x y $ - ---- -// With non-text content -$ op(#underline[ul]) a $ diff --git a/tests/typ/math/opticalsize.typ b/tests/typ/math/opticalsize.typ deleted file mode 100644 index 83e2ce3d..00000000 --- a/tests/typ/math/opticalsize.typ +++ /dev/null @@ -1,69 +0,0 @@ -// test optical sized variants in sub/superscripts - ---- - -// Test transition from script to scriptscript. -#[ -#set text(size:20pt) -$ e^(e^(e^(e))) $ -] -A large number: $e^(e^(e^(e)))$. - ---- -// Test prime/double prime via scriptsize -#let prime = [ \u{2032} ] -#let dprime = [ \u{2033} ] -#let tprime = [ \u{2034} ] -$ y^dprime-2y^prime + y = 0 $ -$y^dprime-2y^prime + y = 0$ -$ y^tprime_3 + g^(prime 2) $ - ---- -// Test prime superscript on large symbol -$ scripts(sum_(k in NN))^prime 1/k^2 $ -$sum_(k in NN)^prime 1/k^2$ - ---- -// Test script-script in a fraction. -$ 1/(x^A) $ -#[#set text(size:18pt); $1/(x^A)$] vs. #[#set text(size:14pt); $x^A$] - ---- -// Test dedicated syntax for primes -$a'$, $a'''_b$, $'$, $'''''''$ - ---- -// Test spaces between -$a' ' '$, $' ' '$, $a' '/b$ - ---- -// Test complex prime combinations -$a'_b^c$, $a_b'^c$, $a_b^c'$, $a_b'^c'^d'$ - -$(a'_b')^(c'_d')$, $a'/b'$, $a_b'/c_d'$ - -$∫'$, $∑'$, $ ∑'_S' $ - ---- -// Test attaching primes only -$a' = a^', a_', a_'''^''^'$ - ---- -// Test primes always attaching as scripts -$ x' $ -$ x^' $ -$ attach(x, t: ') $ -$ <' $ -$ attach(<, br: ') $ -$ op(<, limits: #true)' $ -$ limits(<)' $ - ---- -// Test forcefully attaching primes as limits -$ attach(<, t: ') $ -$ <^' $ -$ attach(<, b: ') $ -$ <_' $ - -$ limits(x)^' $ -$ attach(limits(x), t: ') $ diff --git a/tests/typ/math/prime.typ b/tests/typ/math/prime.typ deleted file mode 100644 index 61e0c0b2..00000000 --- a/tests/typ/math/prime.typ +++ /dev/null @@ -1,9 +0,0 @@ -// Test prime symbols after code mode. -#let g = $f$ -#let gg = $f$ - -$ - #(g)' #g' #g ' \ - #g''''''''''''''''' \ - gg' -$ diff --git a/tests/typ/math/root.typ b/tests/typ/math/root.typ deleted file mode 100644 index 6eba1275..00000000 --- a/tests/typ/math/root.typ +++ /dev/null @@ -1,45 +0,0 @@ -// Test roots. - ---- -// Test root with more than one character. -$A = sqrt(x + y) = c$ - ---- -// Test root size with radicals containing attachments. -$ sqrt(a) quad - sqrt(f) quad - sqrt(q) quad - sqrt(a^2) \ - sqrt(n_0) quad - sqrt(b^()) quad - sqrt(b^2) quad - sqrt(q_1^2) $ - ---- -// Test precomposed vs constructed roots. -// 3 and 4 are precomposed. -$sqrt(x)$ -$root(2, x)$ -$root(3, x)$ -$root(4, x)$ -$root(5, x)$ - ---- -// Test large bodies -$ sqrt([|x|]^2 + [|y|]^2) < [|z|] $ -$ v = sqrt((1/2) / (4/5)) - = root(3, (1/2/3) / (4/5/6)) - = root(4, ((1/2) / (3/4)) / ((1/2) / (3/4))) $ - ---- -// Test large index. -$ root(2, x) quad - root(3/(2/1), x) quad - root(1/11, x) quad - root(1/2/3, 1) $ - ---- -// Test shorthand. -$ √2^3 = sqrt(2^3) $ -$ √(x+y) quad ∛x quad ∜x $ -$ (√2+3) = (sqrt(2)+3) $ diff --git a/tests/typ/math/spacing.typ b/tests/typ/math/spacing.typ deleted file mode 100644 index 63a60ae1..00000000 --- a/tests/typ/math/spacing.typ +++ /dev/null @@ -1,48 +0,0 @@ -// Test spacing in math formulas. - ---- -// Test spacing cases. -$ä, +, c, (, )$ \ -$=), (+), {times}$ \ -$⟧<⟦, abs(-), [=$ \ -$a=b, a==b$ \ -$-a, +a$ \ -$a not b$ \ -$a+b, a*b$ \ -$sum x, sum(x)$ \ -$sum product x$ \ -$f(x), zeta(x), "frac"(x)$ \ -$a+dots.c+b$ -$f(x) sin(y)$ ---- -// Test ignored vs non-ignored spaces. -$f (x), f(x)$ \ -$[a|b], [a | b]$ \ -$a"is"b, a "is" b$ - ---- -// Test predefined spacings. -$a thin b, a med b, a thick b, a quad b$ \ -$a = thin b$ \ -$a - b equiv c quad (mod 2)$ - ---- -// Test spacing for set comprehension. -#set page(width: auto) -$ { x in RR | x "is natural" and x < 10 } $ - ---- -// Test spacing for operators with decorations and modifiers on them -#set page(width: auto) -$a equiv b + c - d => e log 5 op("ln") 6$ \ -$a cancel(equiv) b overline(+) c arrow(-) d hat(=>) e cancel(log) 5 dot(op("ln")) 6$ \ -$a overbrace(equiv) b underline(+) c grave(-) d underbracket(=>) e circle(log) 5 caron(op("ln")) 6$ \ -\ -$a attach(equiv, tl: a, tr: b) b attach(limits(+), t: a, b: b) c tilde(-) d breve(=>) e attach(limits(log), t: a, b: b) 5 attach(op("ln"), tr: a, bl: b) 6$ ---- -// Test weak spacing -$integral f(x) dif x$, -// Not weak -$integral f(x) thin dif x$, -// Both are weak, collide -$integral f(x) #h(0.166em, weak: true)dif x$ diff --git a/tests/typ/math/style.typ b/tests/typ/math/style.typ deleted file mode 100644 index f1a38405..00000000 --- a/tests/typ/math/style.typ +++ /dev/null @@ -1,52 +0,0 @@ -// Test text styling in math. - ---- -// Test italic defaults. -$a, A, delta, ϵ, diff, Delta, ϴ$ - ---- -// Test forcing a specific style. -$A, italic(A), upright(A), bold(A), bold(upright(A)), \ - serif(A), sans(A), cal(A), frak(A), mono(A), bb(A), \ - italic(diff), upright(diff), \ - bb("hello") + bold(cal("world")), \ - mono("SQRT")(x) wreath mono(123 + 456)$ - ---- -// Test forcing math size -$a/b, display(a/b), display(a)/display(b), inline(a/b), script(a/b), sscript(a/b) \ - mono(script(a/b)), script(mono(a/b))\ - script(a^b, cramped: #true), script(a^b, cramped: #false)$ - ---- -// Test a few style exceptions. -$h, bb(N), cal(R), Theta, italic(Theta), sans(Theta), sans(italic(Theta)) \ - bb(d), bb(italic(d)), italic(bb(d)), bb(e), bb(italic(e)), italic(bb(e)) \ - bb(i), bb(italic(i)), italic(bb(i)), bb(j), bb(italic(j)), italic(bb(j)) \ - bb(D), bb(italic(D)), italic(bb(D))$ - ---- -// Test a few greek exceptions. -$bb(Gamma) , bb(gamma), bb(Pi), bb(pi), bb(sum)$ - ---- -// Test hebrew exceptions. -$aleph, beth, gimel, daleth$ - ---- -// Test font fallback. -$ よ and 🏳️🌈 $ - ---- -// Test text properties. -$text(#red, "time"^2) + sqrt("place")$ - ---- -// Test different font. -#show math.equation: set text(font: "Fira Math") -$ v := vec(1 + 2, 2 - 4, sqrt(3), arrow(x)) + 1 $ - ---- -// Test using rules for symbols -#show sym.tack: it => $#h(1em) it #h(1em)$ -$ a tack b $ diff --git a/tests/typ/math/syntax.typ b/tests/typ/math/syntax.typ deleted file mode 100644 index 503d3031..00000000 --- a/tests/typ/math/syntax.typ +++ /dev/null @@ -1,22 +0,0 @@ -// Test math syntax. - ---- -// Test Unicode math. -$ ∑_(i=0)^ℕ a ∘ b = \u{2211}_(i=0)^NN a compose b $ - ---- -// Test a few shorthands. -$ underline(f' : NN -> RR) \ - n |-> cases( - [|1|] &"if" n >>> 10, - 2 * 3 &"if" n != 5, - 1 - 0 thick &..., - ) $ - ---- -// Test common symbols. -$ dot \ dots \ ast \ tilde \ star $ - ---- -// Error: 1-2 unclosed delimiter -$a diff --git a/tests/typ/math/unbalanced.typ b/tests/typ/math/unbalanced.typ deleted file mode 100644 index 9eeb3bfc..00000000 --- a/tests/typ/math/unbalanced.typ +++ /dev/null @@ -1,6 +0,0 @@ -// Test unbalanced delimiters. - ---- -$ 1/(2 (x) $ -$ 1_(2 y (x) () $ -$ 1/(2 y (x) (2(3)) $ diff --git a/tests/typ/math/underover.typ b/tests/typ/math/underover.typ deleted file mode 100644 index f0f67308..00000000 --- a/tests/typ/math/underover.typ +++ /dev/null @@ -1,21 +0,0 @@ -// Test under/over things. - ---- -// Test braces. -$ x = underbrace( - 1 + 2 + ... + 5, - underbrace("numbers", x + y) -) $ - ---- -// Test lines and brackets. -$ x = overbracket( - overline(underline(x + y)), - 1 + 2 + ... + 5, -) $ - ---- -// Test brackets. -$ underbracket([1, 2/3], "relevant stuff") - arrow.l.r.double.long - overbracket([4/5,6], "irrelevant stuff") $ diff --git a/tests/typ/math/vec.typ b/tests/typ/math/vec.typ deleted file mode 100644 index 445b8104..00000000 --- a/tests/typ/math/vec.typ +++ /dev/null @@ -1,14 +0,0 @@ -// Test vectors. - ---- -// Test wide cell. -$ v = vec(1, 2+3, 4) $ - ---- -// Test alternative delimiter. -#set math.vec(delim: "[") -$ vec(1, 2) $ - ---- -// Error: 22-25 expected "(", "[", "{", "|", "||", or none -#set math.vec(delim: "%") diff --git a/tests/typ/meta/bibliography-full.typ b/tests/typ/meta/bibliography-full.typ deleted file mode 100644 index 9b652cd2..00000000 --- a/tests/typ/meta/bibliography-full.typ +++ /dev/null @@ -1,5 +0,0 @@ -// Test the full bibliography. - ---- -#set page(paper: "a6", height: 170mm) -#bibliography("/assets/bib/works.bib", full: true) diff --git a/tests/typ/meta/bibliography-ordering.typ b/tests/typ/meta/bibliography-ordering.typ deleted file mode 100644 index 4732ad68..00000000 --- a/tests/typ/meta/bibliography-ordering.typ +++ /dev/null @@ -1,16 +0,0 @@ -#set page(width: 300pt) - -@mcintosh_anxiety -@psychology25 -@netwok -@issue201 -@arrgh -@quark -@distress, -@glacier-melt -@issue201 -@tolkien54 -@sharing -@restful - -#bibliography("/assets/bib/works.bib") diff --git a/tests/typ/meta/bibliography.typ b/tests/typ/meta/bibliography.typ deleted file mode 100644 index 107f790e..00000000 --- a/tests/typ/meta/bibliography.typ +++ /dev/null @@ -1,44 +0,0 @@ -// Test citations and bibliographies. - ---- -#set page(width: 200pt) - -= Details -See also @arrgh #cite(<distress>, supplement: [p.~22]), @arrgh[p.~4], and @distress[p.~5]. -#bibliography("/assets/bib/works.bib") - ---- -// Test unconventional order. -#set page(width: 200pt) -#bibliography( - "/assets/bib/works.bib", - title: [Works to be cited], - style: "chicago-author-date", -) -#line(length: 100%) - -As described by #cite(<netwok>, form: "prose"), -the net-work is a creature of its own. -This is close to piratery! @arrgh -And quark! @quark - ---- -#set page(width: 200pt) -#set heading(numbering: "1.") -#show bibliography: set heading(numbering: "1.") - -= Multiple Bibs -Now we have multiple bibliographies containing @glacier-melt @keshav2007read -#bibliography(("/assets/bib/works.bib", "/assets/bib/works_too.bib")) - ---- -// Test ambiguous reference. -= Introduction <arrgh> - -// Error: 1-7 label occurs in the document and its bibliography -@arrgh -#bibliography("/assets/bib/works.bib") - ---- -// Error: 15-65 duplicate bibliography keys: netwok, issue201, arrgh, quark, distress, glacier-melt, tolkien54, DBLP:books/lib/Knuth86a, sharing, restful, mcintosh_anxiety, psychology25 -#bibliography(("/assets/bib/works.bib", "/assets/bib/works.bib")) diff --git a/tests/typ/meta/cite-footnote.typ b/tests/typ/meta/cite-footnote.typ deleted file mode 100644 index c6eff59d..00000000 --- a/tests/typ/meta/cite-footnote.typ +++ /dev/null @@ -1,5 +0,0 @@ -Hello @netwok -And again: @netwok - -#pagebreak() -#bibliography("/assets/bib/works.bib", style: "chicago-notes") diff --git a/tests/typ/meta/cite-form.typ b/tests/typ/meta/cite-form.typ deleted file mode 100644 index 343981d7..00000000 --- a/tests/typ/meta/cite-form.typ +++ /dev/null @@ -1,10 +0,0 @@ -// Test citation forms. - ---- -#set page(width: 200pt) - -Nothing: #cite(<arrgh>, form: none) - -#cite(<netwok>, form: "prose") say stuff. - -#bibliography("/assets/bib/works.bib", style: "apa") diff --git a/tests/typ/meta/cite-group.typ b/tests/typ/meta/cite-group.typ deleted file mode 100644 index 331c87ca..00000000 --- a/tests/typ/meta/cite-group.typ +++ /dev/null @@ -1,19 +0,0 @@ -// Test citation grouping. - ---- -A#[@netwok@arrgh]B \ -A@netwok@arrgh B \ -A@netwok @arrgh B \ -A@netwok @arrgh. B \ - -A @netwok#[@arrgh]B \ -A @netwok@arrgh, B \ -A @netwok @arrgh, B \ -A @netwok @arrgh. B \ - -A#[@netwok @arrgh @quark]B. \ -A @netwok @arrgh @quark B. \ -A @netwok @arrgh @quark, B. - -#set text(0pt) -#bibliography("/assets/bib/works.bib") diff --git a/tests/typ/meta/context-compatibility.typ b/tests/typ/meta/context-compatibility.typ deleted file mode 100644 index 60124255..00000000 --- a/tests/typ/meta/context-compatibility.typ +++ /dev/null @@ -1,29 +0,0 @@ -// Test compatibility with the pre-context way of things. -// Ref: false - ---- -#let s = state("x", 0) -#let compute(expr) = [ - #s.update(x => - eval(expr.replace("x", str(x))) - ) - New value is #s.display(). -] - -#locate(loc => { - let elem = query(<here>, loc).first() - test(s.at(elem.location()), 13) -}) - -#compute("10") \ -#compute("x + 3") \ -*Here.* <here> \ -#compute("x * 2") \ -#compute("x - 5") - ---- -#style(styles => measure([it], styles).width < 20pt) - ---- -#counter(heading).update(10) -#counter(heading).display(n => test(n, 10)) diff --git a/tests/typ/meta/context.typ b/tests/typ/meta/context.typ deleted file mode 100644 index 729d9fa2..00000000 --- a/tests/typ/meta/context.typ +++ /dev/null @@ -1,181 +0,0 @@ -// Test context expressions. -// Ref: false - ---- -// Test that context body is parsed as atomic expression. -#let c = [#context "hello".] -#test(c.children.first().func(), (context none).func()) -#test(c.children.last(), [.]) - ---- -// Test that manual construction is forbidden. -// Error: 2-25 cannot be constructed manually -#(context none).func()() - ---- -// Test that `here()` yields the context element's location. -#context test(query(here()).first().func(), (context none).func()) - ---- -// Test whether context is retained in nested function. -#let translate(..args) = args.named().at(text.lang) -#set text(lang: "de") -#context test(translate(de: "Inhalt", en: "Contents"), "Inhalt") - ---- -// Test whether context is retained in built-in callback. -#set text(lang: "de") -#context test( - ("en", "de", "fr").sorted(key: v => v != text.lang), - ("de", "en", "fr"), -) - ---- -// Test `locate` + `here`. -#context test(here().position().y, 10pt) - ---- -// Test `locate`. -#v(10pt) -= Introduction <intro> -#context test(locate(<intro>).position().y, 20pt) - ---- -// Error: 10-25 label `<intro>` does not exist in the document -#context locate(<intro>) - ---- -= Introduction <intro> -= Introduction <intro> - -// Error: 10-25 label `<intro>` occurs multiple times in the document -#context locate(<intro>) - ---- -#v(10pt) -= Introduction <intro> -#context test(locate(heading).position().y, 20pt) - ---- -// Error: 10-25 selector does not match any element -#context locate(heading) - ---- -= Introduction <intro> -= Introduction <intro> - -// Error: 10-25 selector matches multiple elements -#context locate(heading) - ---- -// Test `counter`. -#let c = counter("heading") -#c.update(2) -#c.update(n => n + 2) -#context test(c.get(), (4,)) -#c.update(n => n - 3) -#context test(c.at(here()), (1,)) - ---- -// Test `state.at` outside of context. -// Error: 2-26 can only be used when context is known -// Hint: 2-26 try wrapping this in a `context` expression -// Hint: 2-26 the `context` expression should wrap everything that depends on this function -#state("key").at(<label>) - ---- -// Test `counter.at` outside of context. -// Error: 2-28 can only be used when context is known -// Hint: 2-28 try wrapping this in a `context` expression -// Hint: 2-28 the `context` expression should wrap everything that depends on this function -#counter("key").at(<label>) - ---- -// Test `measure`. -#let f(lo, hi) = context { - let h = measure[Hello].height - assert(h > lo) - assert(h < hi) -} -#text(10pt, f(6pt, 8pt)) -#text(20pt, f(13pt, 14pt)) - ---- -// Test basic get rule. -#context test(text.lang, "en") -#set text(lang: "de") -#context test(text.lang, "de") -#text(lang: "es", context test(text.lang, "es")) - ---- -// Test folding. -#set rect(stroke: red) -#context { - test(type(rect.stroke), stroke) - test(rect.stroke.paint, red) -} -#[ - #set rect(stroke: 4pt) - #context test(rect.stroke, 4pt + red) -] -#context test(rect.stroke, stroke(red)) - ---- -// We have one collision: `figure.caption` could be both the element and a get -// rule for the `caption` field, which is settable. We always prefer the -// element. It's unfortunate, but probably nobody writes -// `set figure(caption: ..)` anyway. -#test(type(figure.caption), function) -#context test(type(figure.caption), function) - ---- -// Error: 10-31 Assertion failed: "en" != "de" -#context test(text.lang, "de") - ---- -// Error: 15-20 function `text` does not contain field `langs` -#context text.langs - ---- -// Error: 18-22 function `heading` does not contain field `body` -#context heading.body - ---- -// Error: 7-11 can only be used when context is known -// Hint: 7-11 try wrapping this in a `context` expression -// Hint: 7-11 the `context` expression should wrap everything that depends on this function -#text.lang - ---- -// Error: 7-12 function `text` does not contain field `langs` -#text.langs - ---- -// Error: 10-14 function `heading` does not contain field `body` -#heading.body - ---- -// Test that show rule establishes context. -#set heading(numbering: "1.") -#show heading: it => test( - counter(heading).get(), - (intro: (1,), back: (2,)).at(str(it.label)), -) - -= Introduction <intro> -= Background <back> - ---- -// Test that show rule on non-locatable element allows `query`. -// Error: 18-47 Assertion failed: 2 != 3 -#show emph: _ => test(query(heading).len(), 3) -#show strong: _ => test(query(heading).len(), 2) -= Introduction -= Background -*Hi* _there_ - ---- -// Test error when captured variable is assigned to. -#let i = 0 -// Error: 11-12 variables from outside the context expression are read-only and cannot be modified -#context (i = 1) diff --git a/tests/typ/meta/counter-page.typ b/tests/typ/meta/counter-page.typ deleted file mode 100644 index 54134b6e..00000000 --- a/tests/typ/meta/counter-page.typ +++ /dev/null @@ -1,10 +0,0 @@ -// Test the page counter. - -#set page(height: 50pt, margin: (bottom: 20pt, rest: 10pt)) -#lorem(12) -#set page(numbering: "(i)") -#lorem(6) -#pagebreak() -#set page(numbering: "1 / 1") -#counter(page).update(1) -#lorem(20) diff --git a/tests/typ/meta/counter.typ b/tests/typ/meta/counter.typ deleted file mode 100644 index 6d72f246..00000000 --- a/tests/typ/meta/counter.typ +++ /dev/null @@ -1,52 +0,0 @@ -// Test counters. - ---- -// Count with string key. -#let mine = counter("mine!") - -Final: #context mine.final().at(0) \ -#mine.step() -First: #context mine.display() \ -#mine.update(7) -#context mine.display("1 of 1", both: true) \ -#mine.step() -#mine.step() -Second: #context mine.display("I") -#mine.update(n => n * 2) -#mine.step() - ---- -// Count labels. -#let label = <heya> -#let count = context counter(label).display() -#let elem(it) = [#box(it) #label] - -#elem[hey, there!] #count \ -#elem[more here!] #count - ---- -// Count headings. -#set heading(numbering: "1.a.") -#show heading: set text(10pt) -#counter(heading).step() - -= Alpha -In #context counter(heading).display() -== Beta - -#set heading(numbering: none) -= Gamma -#heading(numbering: "I.")[Delta] - -At Beta, it was #context { - let it = query(heading).find(it => it.body == [Beta]) - numbering(it.numbering, ..counter(heading).at(it.location())) -} - ---- -// Count figures. -#figure(numbering: "A", caption: [Four 'A's], kind: image, supplement: "Figure")[_AAAA!_] -#figure(numbering: none, caption: [Four 'B's], kind: image, supplement: "Figure")[_BBBB!_] -#figure(caption: [Four 'C's], kind: image, supplement: "Figure")[_CCCC!_] -#counter(figure.where(kind: image)).update(n => n + 3) -#figure(caption: [Four 'D's], kind: image, supplement: "Figure")[_DDDD!_] diff --git a/tests/typ/meta/document.typ b/tests/typ/meta/document.typ deleted file mode 100644 index b058bd96..00000000 --- a/tests/typ/meta/document.typ +++ /dev/null @@ -1,49 +0,0 @@ -// Test document and page-level styles. - ---- -// This is okay. -#set document(title: [Hello]) -What's up? - ---- -// This, too. -// Ref: false -#set document(author: ("A", "B"), date: datetime.today()) - ---- -// Error: 21-28 expected datetime, none, or auto, found string -#set document(date: "today") - ---- -// This, too. -// Error: 23-29 expected string, found integer -#set document(author: (123,)) -What's up? - ---- -Hello - -// Error: 2-30 document set rules must appear before any content -#set document(title: [Hello]) - ---- -// Error: 2-12 can only be used in set rules -#document() - ---- -#box[ - // Error: 4-32 document set rules are not allowed inside of containers - #set document(title: [Hello]) -] - ---- -#box[ - // Error: 4-18 page configuration is not allowed inside of containers - #set page("a4") -] - ---- -#box[ - // Error: 4-15 pagebreaks are not allowed inside of containers - #pagebreak() -] diff --git a/tests/typ/meta/figure-caption.typ b/tests/typ/meta/figure-caption.typ deleted file mode 100644 index 0cdc2bbb..00000000 --- a/tests/typ/meta/figure-caption.typ +++ /dev/null @@ -1,64 +0,0 @@ -// Test figure captions. - ---- -// Test figure.caption element -#show figure.caption: emph - -#figure( - [Not italicized], - caption: [Italicized], -) - ---- -// Test figure.caption element for specific figure kinds -#show figure.caption.where(kind: table): underline - -#figure( - [Not a table], - caption: [Not underlined], -) - -#figure( - table[A table], - caption: [Underlined], -) - ---- -// Test creating custom figure and custom caption - -#let gap = 0.7em -#show figure.where(kind: "custom"): it => rect(inset: gap, { - align(center, it.body) - v(gap, weak: true) - line(length: 100%) - v(gap, weak: true) - align(center, it.caption) -}) - -#figure( - [A figure], - kind: "custom", - caption: [Hi], - supplement: [A], -) - -#show figure.caption: it => emph[ - #it.body - (#it.supplement - #context it.counter.display(it.numbering)) -] - -#figure( - [Another figure], - kind: "custom", - caption: [Hi], - supplement: [B], -) - ---- -// Ref: false -#set figure.caption(position: top) - ---- -// Error: 31-38 expected `top` or `bottom`, found horizon -#set figure.caption(position: horizon) diff --git a/tests/typ/meta/figure-localization.typ b/tests/typ/meta/figure-localization.typ deleted file mode 100644 index 144d9d67..00000000 --- a/tests/typ/meta/figure-localization.typ +++ /dev/null @@ -1,34 +0,0 @@ -// Test localization-related figure features. - ---- -// Test French -#set text(lang: "fr") -#figure( - circle(), - caption: [Un cercle.], -) - ---- -// Test Chinese -#set text(lang: "zh") -#figure( - rect(), - caption: [一个矩形], -) - ---- -// Test Russian -#set text(lang: "ru") - -#figure( - polygon.regular(size: 1cm, vertices: 8), - caption: [Пятиугольник], -) - ---- -// Test Greek -#set text(lang: "gr") -#figure( - circle(), - caption: [Ένας κύκλος.], -) diff --git a/tests/typ/meta/figure.typ b/tests/typ/meta/figure.typ deleted file mode 100644 index b6c1bfd6..00000000 --- a/tests/typ/meta/figure.typ +++ /dev/null @@ -1,111 +0,0 @@ -// Test figures. - ---- -#set page(width: 150pt) -#set figure(numbering: "I") - -We can clearly see that @fig-cylinder and -@tab-complex are relevant in this context. - -#figure( - table(columns: 2)[a][b], - caption: [The basic table.], -) <tab-basic> - -#figure( - pad(y: -6pt, image("/assets/images/cylinder.svg", height: 2cm)), - caption: [The basic shapes.], - numbering: "I", -) <fig-cylinder> - -#figure( - table(columns: 3)[a][b][c][d][e][f], - caption: [The complex table.], -) <tab-complex> - ---- - -// Testing figures with tables. -#figure( - table( - columns: 2, - [Second cylinder], - image("/assets/images/cylinder.svg"), - ), - caption: "A table containing images." -) <fig-image-in-table> - ---- - -// Testing show rules with figures with a simple theorem display -#show figure.where(kind: "theorem"): it => { - let name = none - if not it.caption == none { - name = [ #emph(it.caption.body)] - } else { - name = [] - } - - let title = none - if not it.numbering == none { - title = it.supplement - if not it.numbering == none { - title += " " + it.counter.display(it.numbering) - } - } - title = strong(title) - pad( - top: 0em, bottom: 0em, - block( - fill: green.lighten(90%), - stroke: 1pt + green, - inset: 10pt, - width: 100%, - radius: 5pt, - breakable: false, - [#title#name#h(0.1em):#h(0.2em)#it.body#v(0.5em)] - ) - ) -} - -#set page(width: 150pt) -#figure( - $a^2 + b^2 = c^2$, - supplement: "Theorem", - kind: "theorem", - caption: "Pythagoras' theorem.", - numbering: "1", -) <fig-formula> - -#figure( - $a^2 + b^2 = c^2$, - supplement: "Theorem", - kind: "theorem", - caption: "Another Pythagoras' theorem.", - numbering: none, -) <fig-formula> - -#figure( - ```rust - fn main() { - println!("Hello!"); - } - ```, - caption: [Hello world in _rust_], -) - ---- -// Test breakable figures -#set page(height: 6em) -#show figure: set block(breakable: true) - -#figure(table[a][b][c][d][e], caption: [A table]) - ---- -// Test custom separator for figure caption -#set figure.caption(separator: [ --- ]) - -#figure( - table(columns: 2)[a][b], - caption: [The table with custom separator.], -) diff --git a/tests/typ/meta/footnote-break.typ b/tests/typ/meta/footnote-break.typ deleted file mode 100644 index 9e213aeb..00000000 --- a/tests/typ/meta/footnote-break.typ +++ /dev/null @@ -1,16 +0,0 @@ -// Test footnotes that break across pages. - ---- -#set page(height: 200pt) - -#lorem(5) -#footnote[ // 1 - A simple footnote. - #footnote[Well, not that simple ...] // 2 -] -#lorem(15) -#footnote[Another footnote: #lorem(30)] // 3 -#lorem(15) -#footnote[My fourth footnote: #lorem(50)] // 4 -#lorem(15) -#footnote[And a final footnote.] // 5 diff --git a/tests/typ/meta/footnote-columns.typ b/tests/typ/meta/footnote-columns.typ deleted file mode 100644 index 0dc88930..00000000 --- a/tests/typ/meta/footnote-columns.typ +++ /dev/null @@ -1,9 +0,0 @@ -// Test footnotes in columns, even those -// that are not enabled via `set page`. - ---- -#set page(height: 120pt) -#align(center, strong[Title]) -#show: columns.with(2) -#lorem(3) #footnote(lorem(6)) -Hello there #footnote(lorem(2)) diff --git a/tests/typ/meta/footnote-container.typ b/tests/typ/meta/footnote-container.typ deleted file mode 100644 index 2fa14fac..00000000 --- a/tests/typ/meta/footnote-container.typ +++ /dev/null @@ -1,32 +0,0 @@ -// Test footnotes in containers. - ---- -// Test footnote in caption. -Read the docs #footnote[https://typst.app/docs]! -#figure( - image("/assets/images/graph.png", width: 70%), - caption: [ - A graph #footnote[A _graph_ is a structure with nodes and edges.] - ] -) -More #footnote[just for ...] footnotes #footnote[... testing. :)] - ---- -// Test duplicate footnotes. -#let lang = footnote[Languages.] -#let nums = footnote[Numbers.] - -/ "Hello": A word #lang -/ "123": A number #nums - -- "Hello" #lang -- "123" #nums - -+ "Hello" #lang -+ "123" #nums - -#table( - columns: 2, - [Hello], [A word #lang], - [123], [A number #nums], -) diff --git a/tests/typ/meta/footnote-invariant.typ b/tests/typ/meta/footnote-invariant.typ deleted file mode 100644 index e4d6ded1..00000000 --- a/tests/typ/meta/footnote-invariant.typ +++ /dev/null @@ -1,9 +0,0 @@ -// Ensure that a footnote and the first line of its entry -// always end up on the same page. - ---- -#set page(height: 120pt) - -#lorem(13) - -There #footnote(lorem(20)) diff --git a/tests/typ/meta/footnote-refs.typ b/tests/typ/meta/footnote-refs.typ deleted file mode 100644 index 0caee7bc..00000000 --- a/tests/typ/meta/footnote-refs.typ +++ /dev/null @@ -1,40 +0,0 @@ -// Test references to footnotes. - ---- -A footnote #footnote[Hi]<fn> \ -A reference to it @fn - ---- -// Multiple footnotes are refs -First #footnote[A]<fn1> \ -Second #footnote[B]<fn2> \ -First ref @fn1 \ -Third #footnote[C] \ -Fourth #footnote[D]<fn4> \ -Fourth ref @fn4 \ -Second ref @fn2 \ -Second ref again @fn2 - ---- -// Forward reference -Usage @fn \ -Definition #footnote[Hi]<fn> - ---- -// Footnote ref in footnote -#footnote[Reference to next @fn] -#footnote[Reference to myself @fn]<fn> -#footnote[Reference to previous @fn] - ---- -// Styling -#show footnote: text.with(fill: red) -Real #footnote[...]<fn> \ -Ref @fn - ---- -// Footnote call with label -#footnote(<fn>) -#footnote[Hi]<fn> -#ref(<fn>) -#footnote(<fn>) diff --git a/tests/typ/meta/footnote-table.typ b/tests/typ/meta/footnote-table.typ deleted file mode 100644 index a52d28ba..00000000 --- a/tests/typ/meta/footnote-table.typ +++ /dev/null @@ -1,23 +0,0 @@ -// Test footnotes in tables. When the table spans multiple pages, the footnotes -// will all be after the table, but it shouldn't create any empty pages. ---- - -#set page(height: 100pt) - -= Tables -#table( - columns: 2, - [Hello footnote #footnote[This is a footnote.]], - [This is more text], - [This cell - #footnote[This footnote is not on the same page] - breaks over multiple pages.], - image("/assets/images/tiger.jpg"), -) - -#table( - columns: 3, - ..range(1, 10) - .map(numbering.with("a")) - .map(v => upper(v) + footnote(v)) -) diff --git a/tests/typ/meta/footnote.typ b/tests/typ/meta/footnote.typ deleted file mode 100644 index 8f56fea2..00000000 --- a/tests/typ/meta/footnote.typ +++ /dev/null @@ -1,34 +0,0 @@ -// Test footnotes. - ---- -#footnote[Hi] - ---- -// Test space collapsing before footnote. -A#footnote[A] \ -A #footnote[A] - ---- -// Test nested footnotes. -First \ -Second #footnote[A, #footnote[B, #footnote[C]]] \ -Third #footnote[D, #footnote[E]] \ -Fourth - ---- -// Currently, numbers a bit out of order if a nested footnote ends up in the -// same frame as another one. :( -#footnote[A, #footnote[B]], #footnote[C] - ---- -// Test customization. -#show footnote: set text(red) -#show footnote.entry: set text(8pt, style: "italic") -#set footnote.entry( - indent: 0pt, - gap: 0.6em, - clearance: 0.3em, - separator: repeat[.], -) - -Beautiful footnotes. #footnote[Wonderful, aren't they?] diff --git a/tests/typ/meta/heading.typ b/tests/typ/meta/heading.typ deleted file mode 100644 index a253913e..00000000 --- a/tests/typ/meta/heading.typ +++ /dev/null @@ -1,73 +0,0 @@ -// Test headings. - ---- -// Different number of equals signs. - -= Level 1 -== Level 2 -=== Level 3 - -// After three, it stops shrinking. -=========== Level 11 - ---- -// Heading vs. no heading. - -// Parsed as headings if at start of the context. -/**/ = Level 1 -#[== Level 2] -#box[=== Level 3] - -// Not at the start of the context. -No = heading - -// Escaped. -\= No heading - ---- -// Blocks can continue the heading. - -= #[This -is -multiline. -] - -= This - is not. - ---- -// Test styling. -#show heading.where(level: 5): it => block( - text(font: "Roboto", fill: eastern, it.body + [!]) -) - -= Heading -===== Heading 🌍 -#heading(level: 5)[Heading] - ---- -// Test setting the starting offset. -#set heading(numbering: "1.1") -#show heading.where(level: 2): set text(blue) -= Level 1 - -#heading(depth: 1)[We're twins] -#heading(level: 1)[We're twins] - -== Real level 2 - -#set heading(offset: 1) -= Fake level 2 -== Fake level 3 - ---- -// Passing level directly still overrides all other set values -#set heading(numbering: "1.1", offset: 1) -#heading(level: 1)[Still level 1] - ---- -// Edge cases. -#set heading(numbering: "1.") -= -Not in heading -=Nope diff --git a/tests/typ/meta/link.typ b/tests/typ/meta/link.typ deleted file mode 100644 index dd5bffa8..00000000 --- a/tests/typ/meta/link.typ +++ /dev/null @@ -1,77 +0,0 @@ -// Test hyperlinking. - ---- -// Link syntax. -https://example.com/ - -// Link with body. -#link("https://typst.org/")[Some text text text] - -// With line break. -This link appears #link("https://google.com/")[in the middle of] a paragraph. - -// Certain prefixes are trimmed when using the `link` function. -Contact #link("mailto:hi@typst.app") or -call #link("tel:123") for more information. - ---- -// Test that the period is trimmed. -#show link: underline -https://a.b.?q=%10#. \ -Wahttp://link \ -Nohttps:\//link \ -Nohttp\://comment - ---- -// Verify that brackets are included in links. -https://[::1]:8080/ \ -https://example.com/(paren) \ -https://example.com/#(((nested))) \ - ---- -// Check that unbalanced brackets are not included in links. -#[https://example.com/] \ -https://example.com/) - ---- -// Verify that opening brackets without closing brackets throw an error. -// Error: 1-22 automatic links cannot contain unbalanced brackets, use the `link` function instead -https://exam(ple.com/ - ---- -// Styled with underline and color. -#show link: it => underline(text(fill: rgb("283663"), it)) -You could also make the -#link("https://html5zombo.com/")[link look way more typical.] - ---- -// Transformed link. -#set page(height: 60pt) -#let mylink = link("https://typst.org/")[LINK] -My cool #box(move(dx: 0.7cm, dy: 0.7cm, rotate(10deg, scale(200%, mylink)))) - ---- -// Link containing a block. -#link("https://example.com/", block[ - My cool rhino - #box(move(dx: 10pt, image("/assets/images/rhino.png", width: 1cm))) -]) - ---- -// Link to page one. -#link((page: 1, x: 10pt, y: 20pt))[Back to the start] - ---- -// Test link to label. -Text <hey> -#link(<hey>)[Go to text.] - ---- -// Error: 2-20 label `<hey>` does not exist in the document -#link(<hey>)[Nope.] - ---- -Text <hey> -Text <hey> -// Error: 2-20 label `<hey>` occurs multiple times in the document -#link(<hey>)[Nope.] diff --git a/tests/typ/meta/numbering.typ b/tests/typ/meta/numbering.typ deleted file mode 100644 index 9c0c9b66..00000000 --- a/tests/typ/meta/numbering.typ +++ /dev/null @@ -1,103 +0,0 @@ -// Test integrated numbering patterns. - ---- -#for i in range(0, 9) { - numbering("*", i) - [ and ] - numbering("I.a", i, i) - [ for #i \ ] -} - ---- -#for i in range(0, 4) { - numbering("A", i) - [ for #i \ ] -} -... \ -#for i in range(26, 30) { - numbering("A", i) - [ for #i \ ] -} -... \ -#for i in range(702, 706) { - numbering("A", i) - [ for #i \ ] -} - ---- -#set text(lang: "he") -#for i in range(9, 21, step: 2) { - numbering("א.", i) - [ עבור #i \ ] -} - ---- -#set text(lang: "zh", font: ("Linux Libertine", "Noto Serif CJK SC")) -#for i in range(9, 21, step: 2){ - numbering("一", i) - [ and ] - numbering("壹", i) - [ for #i \ ] -} - ---- -#set text(lang: "ja", font: ("Linux Libertine", "Noto Serif CJK JP")) -#for i in range(0, 4) { - numbering("イ", i) - [ (or ] - numbering("い", i) - [) for #i \ ] -} -... \ -#for i in range(47, 51) { - numbering("イ", i) - [ (or ] - numbering("い", i) - [) for #i \ ] -} -... \ -#for i in range(2256, 2260) { - numbering("イ", i) - [ for #i \ ] -} - ---- -#set text(lang: "ko", font: ("Linux Libertine", "Noto Serif CJK KR")) -#for i in range(0, 4) { - numbering("가", i) - [ (or ] - numbering("ㄱ", i) - [) for #i \ ] -} -... \ -#for i in range(47, 51) { - numbering("가", i) - [ (or ] - numbering("ㄱ", i) - [) for #i \ ] -} -... \ -#for i in range(2256, 2260) { - numbering("ㄱ", i) - [ for #i \ ] -} - ---- -#set text(lang: "jp", font: ("Linux Libertine", "Noto Serif CJK JP")) -#for i in range(0, 9) { - numbering("あ", i) - [ and ] - numbering("I.あ", i, i) - [ for #i \ ] -} - -#for i in range(0, 9) { - numbering("ア", i) - [ and ] - numbering("I.ア", i, i) - [ for #i \ ] -} - ---- -// Error: 17-19 number must be at least zero -#numbering("1", -1) diff --git a/tests/typ/meta/outline-entry.typ b/tests/typ/meta/outline-entry.typ deleted file mode 100644 index 74a785a9..00000000 --- a/tests/typ/meta/outline-entry.typ +++ /dev/null @@ -1,59 +0,0 @@ -// Tests outline entry. - ---- -#set page(width: 150pt) -#set heading(numbering: "1.") - -#show outline.entry.where( - level: 1 -): it => { - v(12pt, weak: true) - strong(it) -} - -#outline(indent: auto) - -#set text(8pt) -#show heading: set block(spacing: 0.65em) - -= Introduction -= Background -== History -== State of the Art -= Analysis -== Setup - ---- -#set page(width: 150pt, numbering: "I", margin: (bottom: 20pt)) -#set heading(numbering: "1.") -#show outline.entry.where(level: 1): it => [ - #let loc = it.element.location() - #let num = numbering(loc.page-numbering(), ..counter(page).at(loc)) - #emph(link(loc, it.body)) - #text(luma(100), box(width: 1fr, repeat[#it.fill.body;·])) - #link(loc, num) -] - -#counter(page).update(3) -#outline(indent: auto, fill: repeat[--]) - -#set text(8pt) -#show heading: set block(spacing: 0.65em) - -= Top heading -== Not top heading -=== Lower heading -=== Lower too -== Also not top - -#pagebreak() -#set page(numbering: "1") - -= Another top heading -== Middle heading -=== Lower heading - ---- -// Error: 2-27 cannot outline metadata -#outline(target: metadata) -#metadata("hello") diff --git a/tests/typ/meta/outline-first-par-indent.typ b/tests/typ/meta/outline-first-par-indent.typ deleted file mode 100644 index 77396634..00000000 --- a/tests/typ/meta/outline-first-par-indent.typ +++ /dev/null @@ -1,15 +0,0 @@ -#set par(first-line-indent: 1.5em) -#set heading(numbering: "1.1.a.") -#show outline.entry.where(level: 1): it => { - v(0.5em, weak: true) - strong(it) -} - -#outline() - -= Introduction -= Background -== History -== State of the Art -= Analysis -== Setup diff --git a/tests/typ/meta/outline-indent.typ b/tests/typ/meta/outline-indent.typ deleted file mode 100644 index b0132d43..00000000 --- a/tests/typ/meta/outline-indent.typ +++ /dev/null @@ -1,60 +0,0 @@ -// Tests outline 'indent' option. - ---- -// With heading numbering -#set page(width: 200pt) -#set heading(numbering: "1.a.") -#outline() -#outline(indent: false) -#outline(indent: true) -#outline(indent: none) -#outline(indent: auto) -#outline(indent: 2em) -#outline(indent: n => ([-], [], [==], [====]).at(n)) -#outline(indent: n => "!" * calc.pow(2, n)) - -= About ACME Corp. - -== History -#lorem(10) - -== Products -#lorem(10) - -=== Categories -#lorem(10) - -==== General -#lorem(10) - ---- -// Without heading numbering -#set page(width: 200pt) -#outline() -#outline(indent: false) -#outline(indent: true) -#outline(indent: none) -#outline(indent: auto) -#outline(indent: n => 2em * n) -#outline(indent: n => ([-], [], [==], [====]).at(n)) -#outline(indent: n => "!" * calc.pow(2, n)) - -= About ACME Corp. - -== History -#lorem(10) - -== Products -#lorem(10) - -=== Categories -#lorem(10) - -==== General -#lorem(10) - ---- -// Error: 2-35 expected relative length or content, found dictionary -#outline(indent: n => (a: "dict")) - -= Heading diff --git a/tests/typ/meta/outline.typ b/tests/typ/meta/outline.typ deleted file mode 100644 index 1d0bcf75..00000000 --- a/tests/typ/meta/outline.typ +++ /dev/null @@ -1,45 +0,0 @@ -#set page("a7", margin: 20pt, numbering: "1") -#set heading(numbering: "(1/a)") -#show heading.where(level: 1): set text(12pt) -#show heading.where(level: 2): set text(10pt) -#set math.equation(numbering: "1") - -#outline() -#outline(title: [Figures], target: figure) -#outline(title: [Equations], target: math.equation) - -= Introduction -#lorem(12) - -= Analysis -#lorem(10) - -#[ - #set heading(outlined: false) - == Methodology - #lorem(6) -] - -== Math -$x$ is a very useful constant. See it in action: -$ x = x $ - -== Interesting figures -#figure(rect[CENSORED], kind: image, caption: [A picture showing a programmer at work.]) -#figure(table[1x1], caption: [A very small table.]) - -== Programming -```rust -fn main() { - panic!("in the disco"); -} -``` - -==== Deep Stuff -Ok ... - -// Ensure 'bookmarked' option doesn't affect the outline -#set heading(numbering: "(I)", bookmarked: false) - -= #text(blue)[Sum]mary -#lorem(10) diff --git a/tests/typ/meta/page-label.typ b/tests/typ/meta/page-label.typ deleted file mode 100644 index 8d12fb13..00000000 --- a/tests/typ/meta/page-label.typ +++ /dev/null @@ -1,47 +0,0 @@ -#set page(margin: (bottom: 20pt, rest: 10pt)) -#let filler = lorem(20) - -// (i) - (ii). No style opt. because of suffix. -#set page(numbering: "(i)") -#filler -#pagebreak() -#filler - -// 3 - 4. Style opt. Page Label should use /D style. -#set page(numbering: "1") -#filler -#pagebreak() -#filler - -// I - IV. Style opt. Page Label should use /R style and start at 1 again. -#set page(numbering: "I / I") -#counter(page).update(1) -#filler -#pagebreak() -#filler -#pagebreak() -#filler -#pagebreak() -#filler - -// Pre: ほ, Pre: ろ, Pre: は, Pre: に. No style opt. Uses prefix field entirely. -// Counter update without numbering change. -#set page(numbering: "Pre: い") -#filler -#pagebreak() -#filler -#counter(page).update(2) -#filler -#pagebreak() -#filler -#pagebreak() -#filler - -// aa & ba. Style opt only for values <= 26. Page Label uses lower alphabet style. -// Repeats letter each 26 pages or uses numbering directly as prefix. -#set page(numbering: "a") -#counter(page).update(27) -#filler -#pagebreak() -#counter(page).update(53) -#filler diff --git a/tests/typ/meta/query-before-after.typ b/tests/typ/meta/query-before-after.typ deleted file mode 100644 index 5f134093..00000000 --- a/tests/typ/meta/query-before-after.typ +++ /dev/null @@ -1,69 +0,0 @@ - ---- -#set page( - paper: "a7", - numbering: "1 / 1", - margin: (bottom: 1cm, rest: 0.5cm), -) - -#show heading.where(level: 1, outlined: true): it => [ - #it - - #set text(size: 12pt, weight: "regular") - #outline( - title: "Chapter outline", - indent: true, - target: heading - .where(level: 1) - .or(heading.where(level: 2)) - .after(it.location(), inclusive: true) - .before( - heading - .where(level: 1, outlined: true) - .after(it.location(), inclusive: false), - inclusive: false, - ) - ) -] - -#set heading(outlined: true, numbering: "1.") - -= Section 1 -== Subsection 1 -== Subsection 2 -=== Subsubsection 1 -=== Subsubsection 2 -== Subsection 3 - -= Section 2 -== Subsection 1 -== Subsection 2 - -= Section 3 -== Subsection 1 -== Subsection 2 -=== Subsubsection 1 -=== Subsubsection 2 -=== Subsubsection 3 -== Subsection 3 - ---- - -#set page( - paper: "a7", - numbering: "1 / 1", - margin: (bottom: 1cm, rest: 0.5cm), -) - -#set heading(outlined: true, numbering: "1.") - -#context [ - Non-outlined elements: - #(query(selector(heading).and(heading.where(outlined: false))) - .map(it => it.body).join(", ")) -] - -#heading("A", outlined: false) -#heading("B", outlined: true) -#heading("C", outlined: true) -#heading("D", outlined: false) diff --git a/tests/typ/meta/query-figure.typ b/tests/typ/meta/query-figure.typ deleted file mode 100644 index 1fe82372..00000000 --- a/tests/typ/meta/query-figure.typ +++ /dev/null @@ -1,41 +0,0 @@ -// Test a list of figures. - ---- -#set page( - paper: "a7", - numbering: "1 / 1", - margin: (bottom: 1cm, rest: 0.5cm), -) - -#set figure(numbering: "I") -#show figure: set image(width: 80%) - -= List of Figures -#context { - let elements = query(selector(figure).after(here())) - for it in elements [ - Figure - #numbering(it.numbering, - ..counter(figure).at(it.location())): - #it.caption.body - #box(width: 1fr, repeat[.]) - #counter(page).at(it.location()).first() \ - ] -} - -#figure( - image("/assets/images/glacier.jpg"), - caption: [Glacier melting], -) - -#figure( - rect[Just some stand-in text], - kind: image, - supplement: "Figure", - caption: [Stand-in text], -) - -#figure( - image("/assets/images/tiger.jpg"), - caption: [Tiger world], -) diff --git a/tests/typ/meta/query-header.typ b/tests/typ/meta/query-header.typ deleted file mode 100644 index 5cbaa995..00000000 --- a/tests/typ/meta/query-header.typ +++ /dev/null @@ -1,30 +0,0 @@ -// Test creating a header with the query function. - ---- -#set page( - paper: "a7", - margin: (y: 1cm, x: 0.5cm), - header: context { - smallcaps[Typst Academy] - h(1fr) - let after = query(selector(heading).after(here())) - let before = query(selector(heading).before(here())) - let elem = if before.len() != 0 { - before.last() - } else if after.len() != 0 { - after.first() - } - emph(elem.body) - } -) - -#outline() - -= Introduction -#lorem(35) - -= Background -#lorem(35) - -= Approach -#lorem(60) diff --git a/tests/typ/meta/ref.typ b/tests/typ/meta/ref.typ deleted file mode 100644 index 4cc824d7..00000000 --- a/tests/typ/meta/ref.typ +++ /dev/null @@ -1,48 +0,0 @@ -// Test references. - ---- -#set heading(numbering: "1.") - -= Introduction <intro> -See @setup. - -== Setup <setup> -As seen in @intro, we proceed. - ---- -// Error: 1-5 label `<foo>` does not exist in the document -@foo - ---- -= First <foo> -= Second <foo> - -// Error: 1-5 label `<foo>` occurs multiple times in the document -@foo - ---- -#set heading(numbering: "1.", supplement: [Chapter]) -#set math.equation(numbering: "(1)", supplement: [Eq.]) - -= Intro -#figure( - image("/assets/images/cylinder.svg", height: 1cm), - caption: [A cylinder.], - supplement: "Fig", -) <fig1> - -#figure( - image("/assets/images/tiger.jpg", height: 1cm), - caption: [A tiger.], - supplement: "Tig", -) <fig2> - -$ A = 1 $ <eq1> - -#set math.equation(supplement: none) -$ A = 1 $ <eq2> - -@fig1, @fig2, @eq1, (@eq2) - -#set ref(supplement: none) -@fig1, @fig2, @eq1, @eq2 diff --git a/tests/typ/meta/state.typ b/tests/typ/meta/state.typ deleted file mode 100644 index 3fa8ece7..00000000 --- a/tests/typ/meta/state.typ +++ /dev/null @@ -1,56 +0,0 @@ -// Test state. - ---- -#let s = state("hey", "a") -#let double(it) = 2 * it - -#s.update(double) -#s.update(double) -$ 2 + 3 $ -#s.update(double) - -Is: #context s.get(), -Was: #context { - let it = query(math.equation).first() - s.at(it.location()) -}. - ---- -// Try same key with different initial value. -#context state("key", 2).get() -#state("key").update(x => x + 1) -#context state("key", 2).get() -#context state("key", 3).get() -#state("key").update(x => x + 1) -#context state("key", 2).get() - ---- -#set page(width: 200pt) -#set text(8pt) - -#let ls = state("lorem", lorem(1000).split(".")) -#let loremum(count) = { - context ls.get().slice(0, count).join(".").trim() + "." - ls.update(list => list.slice(count)) -} - -#let fs = state("fader", red) -#let trait(title) = block[ - #context text(fill: fs.get())[ - *#title:* #loremum(1) - ] - #fs.update(color => color.lighten(30%)) -] - -#trait[Boldness] -#trait[Adventure] -#trait[Fear] -#trait[Anger] - ---- -// Make sure that a warning is produced if the layout fails to converge. -// Warning: layout did not converge within 5 attempts -// Hint: check if any states or queries are updating themselves -#let s = state("s", 1) -#context s.update(s.final() + 1) -#context s.get() diff --git a/tests/typ/text/baseline.typ b/tests/typ/text/baseline.typ deleted file mode 100644 index c8fbb19d..00000000 --- a/tests/typ/text/baseline.typ +++ /dev/null @@ -1,12 +0,0 @@ -// Test baseline handling. - ---- -Hi #text(1.5em)[You], #text(0.75em)[how are you?] - -Our cockatoo was one of the -#text(baseline: -0.2em)[#box(circle(radius: 2pt)) first] -#text(baseline: 0.2em)[birds #box(circle(radius: 2pt))] -that ever learned to mimic a human voice. - ---- -Hey #box(baseline: 40%, image("/assets/images/tiger.jpg", width: 1.5cm)) there! diff --git a/tests/typ/text/case.typ b/tests/typ/text/case.typ deleted file mode 100644 index 75574f21..00000000 --- a/tests/typ/text/case.typ +++ /dev/null @@ -1,12 +0,0 @@ -// Test the `upper` and `lower` functions. -// Ref: false - ---- -#let memes = "ArE mEmEs gReAt?"; -#test(lower(memes), "are memes great?") -#test(upper(memes), "ARE MEMES GREAT?") -#test(upper("Ελλάδα"), "ΕΛΛΆΔΑ") - ---- -// Error: 8-9 expected string or content, found integer -#upper(1) diff --git a/tests/typ/text/chinese.typ b/tests/typ/text/chinese.typ deleted file mode 100644 index 258d72fd..00000000 --- a/tests/typ/text/chinese.typ +++ /dev/null @@ -1,9 +0,0 @@ -// Test chinese text from Wikipedia. - ---- -#set text(font: "Noto Serif CJK SC") - -是美国广播公司电视剧《迷失》第3季的第22和23集,也是全剧的第71集和72集 -由执行制作人戴蒙·林道夫和卡尔顿·库斯编剧,导演则是另一名执行制作人杰克·本德 -节目于2007年5月23日在美国和加拿大首播,共计吸引了1400万美国观众收看 -本集加上插播广告一共也持续有两个小时 diff --git a/tests/typ/text/copy-paste.typ b/tests/typ/text/copy-paste.typ deleted file mode 100644 index 5d826482..00000000 --- a/tests/typ/text/copy-paste.typ +++ /dev/null @@ -1,8 +0,0 @@ -// Test copy-paste and search in PDF with ligatures -// and Arabic test. Must be tested manually! - ---- -The after fira 🏳️🌈! - -#set text(lang: "ar", font: "Noto Sans Arabic") -مرحبًا diff --git a/tests/typ/text/deco.typ b/tests/typ/text/deco.typ deleted file mode 100644 index cc9b9b3a..00000000 --- a/tests/typ/text/deco.typ +++ /dev/null @@ -1,85 +0,0 @@ -// Test text decorations. - ---- -#let red = rgb("fc0030") - -// Basic strikethrough. -#strike[Statements dreamt up by the utterly deranged.] - -// Move underline down. -#underline(offset: 5pt)[Further below.] - -// Different color. -#underline(stroke: red, evade: false)[Critical information is conveyed here.] - -// Inherits font color. -#text(fill: red, underline[Change with the wind.]) - -// Both over- and underline. -#overline(underline[Running amongst the wolves.]) - ---- -#let redact = strike.with(stroke: 10pt, extent: 0.05em) -#let highlight-custom = strike.with(stroke: 10pt + rgb("abcdef88"), extent: 0.05em) - -// Abuse thickness and transparency for redacting and highlighting stuff. -Sometimes, we work #redact[in secret]. -There might be #highlight-custom[redacted] things. - ---- -// Test stroke folding. -#set underline(stroke: 2pt, offset: 2pt) -#underline(text(red, [DANGER!])) - ---- -// Test highlight. -This is the built-in #highlight[highlight with default color]. -We can also specify a customized value -#highlight(fill: green.lighten(80%))[to highlight]. - ---- -// Test default highlight bounds. -#highlight[ace], -#highlight[base], -#highlight[super], -#highlight[phone #sym.integral] - ---- -// Test a tighter highlight. -#set highlight(top-edge: "x-height", bottom-edge: "baseline") -#highlight[ace], -#highlight[base], -#highlight[super], -#highlight[phone #sym.integral] - ---- -// Test a bounds highlight. -#set highlight(top-edge: "bounds", bottom-edge: "bounds") -#highlight[abc] -#highlight[abc #sym.integral] - ---- -// Test highlight radius -#highlight(radius: 3pt)[abc], -#highlight(radius: 1em)[#lorem(5)] - ---- -// Test highlight stroke -#highlight(stroke: 2pt + blue)[abc] -#highlight(stroke: (top: blue, left: red, bottom: green, right: orange))[abc] -#highlight(stroke: 1pt, radius: 3pt)[#lorem(5)] - ---- -// Test underline background -#set underline(background: true, stroke: (thickness: 0.5em, paint: red, cap: "round")) -#underline[This is in the background] - ---- -// Test overline background -#set overline(background: true, stroke: (thickness: 0.5em, paint: red, cap: "round")) -#overline[This is in the background] - ---- -// Test strike background -#set strike(background: true, stroke: 5pt + red) -#strike[This is in the background] diff --git a/tests/typ/text/edge.typ b/tests/typ/text/edge.typ deleted file mode 100644 index 053576e8..00000000 --- a/tests/typ/text/edge.typ +++ /dev/null @@ -1,39 +0,0 @@ -// Test top and bottom text edge. - ---- -#set page(width: 160pt) -#set text(size: 8pt) - -#let try(top, bottom) = rect(inset: 0pt, fill: conifer)[ - #set text(font: "IBM Plex Mono", top-edge: top, bottom-edge: bottom) - From #top to #bottom -] - -#let try-bounds(top, bottom) = rect(inset: 0pt, fill: conifer)[ - #set text(font: "IBM Plex Mono", top-edge: top, bottom-edge: bottom) - #top to #bottom: "yay, Typst" -] - -#try("ascender", "descender") -#try("ascender", "baseline") -#try("cap-height", "baseline") -#try("x-height", "baseline") -#try-bounds("cap-height", "baseline") -#try-bounds("bounds", "baseline") -#try-bounds("bounds", "bounds") -#try-bounds("x-height", "bounds") - -#try(4pt, -2pt) -#try(1pt + 0.3em, -0.15em) - ---- -// Error: 21-23 expected "ascender", "cap-height", "x-height", "baseline", "bounds", or length, found array -#set text(top-edge: ()) - ---- -// Error: 24-26 expected "baseline", "descender", "bounds", or length -#set text(bottom-edge: "") - ---- -// Error: 24-36 expected "baseline", "descender", "bounds", or length -#set text(bottom-edge: "cap-height") diff --git a/tests/typ/text/em.typ b/tests/typ/text/em.typ deleted file mode 100644 index bf191c1f..00000000 --- a/tests/typ/text/em.typ +++ /dev/null @@ -1,33 +0,0 @@ -// Test font-relative sizing. - ---- -#set text(size: 5pt) -A // 5pt -#[ - #set text(size: 2em) - B // 10pt - #[ - #set text(size: 1.5em + 1pt) - C // 16pt - #text(size: 2em)[D] // 32pt - E // 16pt - ] - F // 10pt -] -G // 5pt - ---- -// Test using ems in arbitrary places. -#set text(size: 5pt) -#set text(size: 2em) -#set square(fill: red) - -#let size = { - let size = 0.25em + 1pt - for _ in range(3) { - size *= 2 - } - size - 3pt -} - -#stack(dir: ltr, spacing: 1fr, square(size: size), square(size: 25pt)) diff --git a/tests/typ/text/emoji.typ b/tests/typ/text/emoji.typ deleted file mode 100644 index f8e0d5b6..00000000 --- a/tests/typ/text/emoji.typ +++ /dev/null @@ -1,18 +0,0 @@ -// Test emoji shaping. - ---- -// This should form a three-member family. -👩👩👦 - -// This should form a pride flag. -🏳️🌈 - -// Skin tone modifier should be applied. -👍🏿 - -// This should be a 1 in a box. -1️⃣ - ---- -// These two shouldn't be affected by a zero-width joiner. -🏞🌋 diff --git a/tests/typ/text/emphasis.typ b/tests/typ/text/emphasis.typ deleted file mode 100644 index 93913dcf..00000000 --- a/tests/typ/text/emphasis.typ +++ /dev/null @@ -1,50 +0,0 @@ -// Test emph and strong. - ---- -// Basic. -_Emphasized and *strong* words!_ - -// Inside of a word it's a normal underscore or star. -hello_world Nutzer*innen - -// CJK characters will not need spaces. -中文一般使用*粗体*或者_楷体_来表示强调。 - -日本語では、*太字*や_斜体_を使って強調します。 - -中文中混有*Strong*和_Empasis_。 - -// Can contain paragraph in nested content block. -_Still #[ - -] emphasized._ - ---- -// Inside of words can still use the functions. -P#strong[art]ly em#emph[phas]ized. - ---- -// Adjusting the delta that strong applies on the weight. -Normal - -#set strong(delta: 300) -*Bold* - -#set strong(delta: 150) -*Medium* and *#[*Bold*]* - ---- -// Error: 6-7 unclosed delimiter -#box[_Scoped] to body. - ---- -// Ends at paragraph break. -// Error: 1-2 unclosed delimiter -_Hello - -World - ---- -// Error: 11-12 unclosed delimiter -// Error: 3-4 unclosed delimiter -#[_Cannot *be interleaved] diff --git a/tests/typ/text/escape.typ b/tests/typ/text/escape.typ deleted file mode 100644 index 901632ba..00000000 --- a/tests/typ/text/escape.typ +++ /dev/null @@ -1,36 +0,0 @@ -// Test escape sequences. - ---- -// Escapable symbols. -\\ \/ \[ \] \{ \} \# \* \_ \+ \= \~ \ -\` \$ \" \' \< \> \@ \( \) \A - -// No need to escape. -( ) ; - -// Escaped comments. -\// -\/\* \*\/ -\/* \*/ * - -// Unicode escape sequence. -\u{1F3D5} == 🏕 - -// Escaped escape sequence. -\u{41} vs. \\u\{41\} - -// Some code stuff in text. -let f() , ; : | + - /= == 12 "string" - -// Escaped dot. -10\. May - ---- -// Unicode codepoint does not exist. -// Error: 1-11 invalid Unicode codepoint: FFFFFF -\u{FFFFFF} - ---- -// Unterminated. -// Error: 1-6 unclosed Unicode escape sequence -\u{41[*Bold*] diff --git a/tests/typ/text/fallback.typ b/tests/typ/text/fallback.typ deleted file mode 100644 index 1db85945..00000000 --- a/tests/typ/text/fallback.typ +++ /dev/null @@ -1,20 +0,0 @@ -// Test font fallback. - ---- -// Font fallback for emoji. -A😀B - -// Font fallback for entire text. -دع النص يمطر عليك - -// Font fallback in right-to-left text. -ب🐈😀سم - -// Multi-layer font fallback. -Aب😀🏞سمB - -// Font fallback with composed emojis and multiple fonts. -01️⃣2 - -// Tofus are rendered with the first font. -A🐈ዲሞB diff --git a/tests/typ/text/features.typ b/tests/typ/text/features.typ deleted file mode 100644 index 69a7064f..00000000 --- a/tests/typ/text/features.typ +++ /dev/null @@ -1,63 +0,0 @@ -// Test OpenType features. - ---- -// Test turning kerning off. -#text(kerning: true)[Tq] \ -#text(kerning: false)[Tq] - ---- -// Test smallcaps. -#smallcaps[Smallcaps] - ---- -// Test alternates and stylistic sets. -#set text(font: "IBM Plex Serif") -a vs #text(alternates: true)[a] \ -ß vs #text(stylistic-set: 5)[ß] - ---- -// Test ligatures. -fi vs. #text(ligatures: false)[No fi] - ---- -// Test number type. -#set text(number-type: "old-style") -0123456789 \ -#text(number-type: auto)[0123456789] - ---- -// Test number width. -#text(number-width: "proportional")[0123456789] \ -#text(number-width: "tabular")[3456789123] \ -#text(number-width: "tabular")[0123456789] - ---- -// Test extra number stuff. -#set text(font: "IBM Plex Serif") -0 vs. #text(slashed-zero: true)[0] \ -1/2 vs. #text(fractions: true)[1/2] - ---- -// Test raw features. -#text(features: ("smcp",))[Smcp] \ -fi vs. #text(features: (liga: 0))[No fi] - ---- -// Error: 26-31 expected integer or none, found boolean -#set text(stylistic-set: false) - ---- -// Error: 26-28 stylistic set must be between 1 and 20 -#set text(stylistic-set: 25) - ---- -// Error: 24-25 expected "lining", "old-style", or auto, found integer -#set text(number-type: 2) - ---- -// Error: 21-26 expected array or dictionary, found boolean -#set text(features: false) - ---- -// Error: 21-35 expected string, found boolean -#set text(features: ("tag", false)) diff --git a/tests/typ/text/font.typ b/tests/typ/text/font.typ deleted file mode 100644 index 736ded41..00000000 --- a/tests/typ/text/font.typ +++ /dev/null @@ -1,66 +0,0 @@ -// Test configuring font properties. - ---- -// Set same font size in three different ways. -#text(20pt)[A] -#text(2em)[A] -#text(size: 15pt + 0.5em)[A] - -// Do nothing. -#text()[Normal] - -// Set style (is available). -#text(style: "italic")[Italic] - -// Set weight (is available). -#text(weight: "bold")[Bold] - -// Set stretch (not available, matching closest). -#text(stretch: 50%)[Condensed] - -// Set font family. -#text(font: "IBM Plex Serif")[Serif] - -// Emoji. -Emoji: 🐪, 🌋, 🏞 - -// Colors. -#[ - #set text(fill: eastern) - This is #text(rgb("FA644B"))[way more] colorful. -] - -// Transparency. -#block(fill: green)[ - #set text(fill: rgb("FF000080")) - This text is transparent. -] - -// Disable font fallback beyond the user-specified list. -// Without disabling, New Computer Modern Math would come to the rescue. -#set text(font: ("PT Sans", "Twitter Color Emoji"), fallback: false) -2π = 𝛼 + 𝛽. ✅ - ---- -// Test string body. -#text("Text") \ -#text(red, "Text") \ -#text(font: "Ubuntu", blue, "Text") \ -#text([Text], teal, font: "IBM Plex Serif") \ -#text(forest, font: "New Computer Modern", [Text]) \ - ---- -// Error: 11-16 unexpected argument -#set text(false) - ---- -// Error: 18-24 expected "normal", "italic", or "oblique" -#set text(style: "bold", weight: "thin") - ---- -// Error: 23-27 unexpected argument -#set text(size: 10pt, 12pt) - ---- -// Error: 11-31 unexpected argument: something -#set text(something: "invalid") diff --git a/tests/typ/text/hyphenate.typ b/tests/typ/text/hyphenate.typ deleted file mode 100644 index 42946a88..00000000 --- a/tests/typ/text/hyphenate.typ +++ /dev/null @@ -1,51 +0,0 @@ -// Test hyphenation. - ---- -// Test hyphenating english and greek. -#set text(hyphenate: true) -#set page(width: auto) -#grid( - columns: (50pt, 50pt), - [Warm welcomes to Typst.], - text(lang: "el")[διαμερίσματα. \ λατρευτός], -) - ---- -// Test disabling hyphenation for short passages. -#set page(width: 110pt) -#set text(hyphenate: true) - -Welcome to wonderful experiences. \ -Welcome to `wonderful` experiences. \ -Welcome to #text(hyphenate: false)[wonderful] experiences. \ -Welcome to wonde#text(hyphenate: false)[rf]ul experiences. \ - -// Test enabling hyphenation for short passages. -#set text(hyphenate: false) -Welcome to wonderful experiences. \ -Welcome to wo#text(hyphenate: true)[nd]erful experiences. \ - ---- -// Hyphenate between shape runs. -#set page(width: 80pt) -#set text(hyphenate: true) -It's a #emph[Tree]beard. - ---- -// Test shy hyphens. -#set text(lang: "de", hyphenate: true) -#grid( - columns: 2 * (20pt,), - gutter: 20pt, - [Barankauf], - [Bar-?ankauf], -) - ---- -// This sequence would confuse hypher if we passed trailing / leading -// punctuation instead of just the words. So this tests that we don't -// do that. The test passes if there's just one hyphenation between -// "net" and "works". -#set page(width: 60pt) -#set text(hyphenate: true) -#h(6pt) networks, the rest. diff --git a/tests/typ/text/lang-with-region.typ b/tests/typ/text/lang-with-region.typ deleted file mode 100644 index f890a00f..00000000 --- a/tests/typ/text/lang-with-region.typ +++ /dev/null @@ -1,16 +0,0 @@ -// Test if text with region works - ---- -// without any region -#set text(font: "Noto Serif CJK TC", lang: "zh") -#outline() - ---- -// with unknown region configured -#set text(font: "Noto Serif CJK TC", lang: "zh", region: "XX") -#outline() - ---- -// with region configured -#set text(font: "Noto Serif CJK TC", lang: "zh", region: "TW") -#outline() diff --git a/tests/typ/text/lang.typ b/tests/typ/text/lang.typ deleted file mode 100644 index 7f1ae1fc..00000000 --- a/tests/typ/text/lang.typ +++ /dev/null @@ -1,59 +0,0 @@ -// Test setting the document language. - ---- -// Ensure that setting the language does have effects. -#set text(hyphenate: true) -#grid( - columns: 2 * (20pt,), - gutter: 1fr, - text(lang: "en")["Eingabeaufforderung"], - text(lang: "de")["Eingabeaufforderung"], -) - ---- -// Test that the language passed to the shaper has an effect. -#set text(font: "Ubuntu") - -// Some lowercase letters are different in Serbian Cyrillic compared to other -// Cyrillic languages. Since there is only one set of Unicode codepoints for -// Cyrillic, these can only be seen when setting the language to Serbian and -// selecting one of the few fonts that support these letterforms. -Бб -#text(lang: "uk")[Бб] -#text(lang: "sr")[Бб] - ---- -// Verify that writing script/language combination has an effect -#{ - set text(size:20pt) - set text(script: "latn", lang: "en") - [Ş ] - set text(script: "latn", lang: "ro") - [Ş ] - set text(script: "grek", lang: "ro") - [Ş ] -} - ---- -// Error: 19-23 expected string or auto, found none -#set text(script: none) - ---- -// Error: 19-23 expected three or four letter script code (ISO 15924 or 'math') -#set text(script: "ab") - ---- -// Error: 17-21 expected string, found none -#set text(lang: none) - ---- -// Error: 17-20 expected two or three letter language code (ISO 639-1/2/3) -#set text(lang: "ӛ") - ---- -// Error: 17-20 expected two or three letter language code (ISO 639-1/2/3) -#set text(lang: "😃") - ---- -// Error: 19-24 expected two letter region code (ISO 3166-1 alpha-2) -#set text(region: "hey") diff --git a/tests/typ/text/linebreak-link.typ b/tests/typ/text/linebreak-link.typ deleted file mode 100644 index 9f6407fa..00000000 --- a/tests/typ/text/linebreak-link.typ +++ /dev/null @@ -1,23 +0,0 @@ -// Test linebreaking of links. - ---- -#link("https://example.com/(ab") \ -#link("https://example.com/(ab)") \ -#link("https://example.com/(paren)") \ -#link("https://example.com/paren)") \ -#link("https://hi.com/%%%%%%%%abcdef") \ - ---- -#set page(width: 240pt) -#set par(justify: true) - -Here's a link https://url.com/data/extern12840%data_urlenc and then there are more -links #link("www.url.com/data/extern12840%data_urlenc") in my text of links -http://mydataurl/hash/12098541029831025981024980124124214/incremental/progress%linkdata_information_setup_my_link_just_never_stops_going/on?query=false - ---- -// Ensure that there's no unconditional break at the end of a link. -#set page(width: 180pt, height: auto, margin: auto) -#set text(11pt) - -For info see #link("https://myhost.tld"). diff --git a/tests/typ/text/linebreak-obj.typ b/tests/typ/text/linebreak-obj.typ deleted file mode 100644 index ebf55f15..00000000 --- a/tests/typ/text/linebreak-obj.typ +++ /dev/null @@ -1,24 +0,0 @@ -// Test linebreaks with after inline elements. - ---- -// Test punctuation after citations. -#set page(width: 162pt) - -They can look for the details in @netwok, -which is the authoritative source. - -#bibliography("/assets/bib/works.bib") - ---- -// Test punctuation after math equations. -#set page(width: 85pt) - -We prove $1 < 2$. \ -We prove $1 < 2$! \ -We prove $1 < 2$? \ -We prove $1 < 2$, \ -We prove $1 < 2$; \ -We prove $1 < 2$: \ -We prove $1 < 2$- \ -We prove $1 < 2$– \ -We prove $1 < 2$— \ diff --git a/tests/typ/text/linebreak.typ b/tests/typ/text/linebreak.typ deleted file mode 100644 index 2ddeb9ed..00000000 --- a/tests/typ/text/linebreak.typ +++ /dev/null @@ -1,60 +0,0 @@ -// Test line breaks. - ---- -// Test overlong word that is not directly after a hard break. -This is a spaceexceedinglylongy. - ---- -// Test two overlong words in a row. -Supercalifragilisticexpialidocious Expialigoricmetrioxidation. - ---- -// Test for non-breaking space and hyphen. -There are non\u{2011}breaking~characters. - ---- -// Test for narrow non-breaking space. -#show "_": sym.space.nobreak.narrow -0.1_g, 1_g, 10_g, 100_g, 1_000_g, 10_000_g, 100_000_g, 1_000_000_g - ---- -// Test that there are no unwanted line break opportunities on run change. -This is partly emp#emph[has]ized. - ---- -Hard #linebreak() break. - ---- -// Test hard break directly after normal break. -Hard break directly after \ normal break. - ---- -// Test consecutive breaks. -Two consecutive \ \ breaks and three \ \ more. - ---- -// Test forcing an empty trailing line. -Trailing break \ \ - ---- -// Test justified breaks. -#set par(justify: true) -With a soft #linebreak(justify: true) -break you can force a break without #linebreak(justify: true) -breaking justification. #linebreak(justify: false) -Nice! - ---- -// Test comments at the end of a line -First part// -Second part - -// Test comments at the end of a line with pre-spacing -First part // -Second part - ---- -// Test linebreak for East Asian languages -ทีวีตรวจทานนอร์ทแฟรีเลคเชอร์โกลด์อัลบัมเชอร์รี่เย้วสโตร์กฤษณ์เคลมเยอบีร่าพ่อค้าบลูเบอร์รี่สหัสวรรษโฮปแคนูโยโย่จูนสตรอว์เบอร์รีซื่อบื้อเยนแบ็กโฮเป็นไงโดนัททอมสเตริโอแคนูวิทย์แดรี่โดนัทวิทย์แอปพริคอทเซอร์ไพรส์ไฮบริดกิฟท์อินเตอร์โซนเซอร์วิสเทียมทานโคโยตี้ม็อบเที่ยงคืนบุญคุณ - - diff --git a/tests/typ/text/lorem.typ b/tests/typ/text/lorem.typ deleted file mode 100644 index 804f804d..00000000 --- a/tests/typ/text/lorem.typ +++ /dev/null @@ -1,32 +0,0 @@ -// Test blind text. - ---- -// Test basic call. -#lorem(19) - ---- -// Test custom paragraphs with user code. -#set text(8pt) - -#{ - let sentences = lorem(59) - .split(".") - .filter(s => s != "") - .map(s => s + ".") - - let used = 0 - for s in sentences { - if used < 2 { - used += 1 - } else { - parbreak() - used = 0 - } - s.trim() - [ ] - } -} - ---- -// Error: 2-9 missing argument: words -#lorem() diff --git a/tests/typ/text/microtype.typ b/tests/typ/text/microtype.typ deleted file mode 100644 index 4c2b4d0b..00000000 --- a/tests/typ/text/microtype.typ +++ /dev/null @@ -1,23 +0,0 @@ -// Test micro-typographical shenanigans. - ---- -// Test hanging punctuation. -#set page(width: 130pt, margin: 15pt) -#set par(justify: true, linebreaks: "simple") -#set text(size: 9pt) -#rect(inset: 0pt, fill: rgb(0, 0, 0, 0), width: 100%)[ - This is a little bit of text that builds up to - hang-ing hyphens and dash---es and then, you know, - some punctuation in the margin. -] - -// Test hanging punctuation with RTL. -#set text(lang: "he", font: ("PT Sans", "Noto Serif Hebrew")) -בנייה נכונה של משפטים ארוכים דורשת ידע בשפה. אז בואו נדבר על מזג האוויר. - ---- -// Test that lone punctuation doesn't overhang into the margin. -#set page(margin: 0pt) -#set align(end) -#set text(dir: rtl) -: diff --git a/tests/typ/text/numbers.typ b/tests/typ/text/numbers.typ deleted file mode 100644 index a35798d1..00000000 --- a/tests/typ/text/numbers.typ +++ /dev/null @@ -1,110 +0,0 @@ -// Test how numbers are displayed. - ---- -// Test numbers in text mode. -12 \ -12.0 \ -3.14 \ -1234567890 \ -0123456789 \ -0 \ -0.0 \ -+0 \ -+0.0 \ --0 \ --0.0 \ --1 \ --3.14 \ --9876543210 \ --0987654321 \ -٣٫١٤ \ --٣٫١٤ \ --¾ \ -#text(fractions: true)[-3/2] \ -2022 - 2023 \ -2022 -- 2023 \ -2022--2023 \ -2022-2023 \ -٢٠٢٢ - ٢٠٢٣ \ -٢٠٢٢ -- ٢٠٢٣ \ -٢٠٢٢--٢٠٢٣ \ -٢٠٢٢-٢٠٢٣ \ --500 -- -400 - ---- -// Test integers. -#12 \ -#1234567890 \ -#0123456789 \ -#0 \ -#(-0) \ -#(-1) \ -#(-9876543210) \ -#(-0987654321) \ -#(4 - 8) - ---- -// Test floats. -#12.0 \ -#3.14 \ -#1234567890.0 \ -#0123456789.0 \ -#0.0 \ -#(-0.0) \ -#(-1.0) \ -#(-9876543210.0) \ -#(-0987654321.0) \ -#(-3.14) \ -#(4.0 - 8.0) - ---- -// Test the `str` function with integers. -#str(12) \ -#str(1234567890) \ -#str(0123456789) \ -#str(0) \ -#str(-0) \ -#str(-1) \ -#str(-9876543210) \ -#str(-0987654321) \ -#str(4 - 8) - ---- -// Test the `str` function with floats. -#str(12.0) \ -#str(3.14) \ -#str(1234567890.0) \ -#str(0123456789.0) \ -#str(0.0) \ -#str(-0.0) \ -#str(-1.0) \ -#str(-9876543210.0) \ -#str(-0987654321.0) \ -#str(-3.14) \ -#str(4.0 - 8.0) - ---- -// Test the `repr` function with integers. -#repr(12) \ -#repr(1234567890) \ -#repr(0123456789) \ -#repr(0) \ -#repr(-0) \ -#repr(-1) \ -#repr(-9876543210) \ -#repr(-0987654321) \ -#repr(4 - 8) - ---- -// Test the `repr` function with floats. -#repr(12.0) \ -#repr(3.14) \ -#repr(1234567890.0) \ -#repr(0123456789.0) \ -#repr(0.0) \ -#repr(-0.0) \ -#repr(-1.0) \ -#repr(-9876543210.0) \ -#repr(-0987654321.0) \ -#repr(-3.14) \ -#repr(4.0 - 8.0) diff --git a/tests/typ/text/quote-nesting.typ b/tests/typ/text/quote-nesting.typ deleted file mode 100644 index 381aaa56..00000000 --- a/tests/typ/text/quote-nesting.typ +++ /dev/null @@ -1,27 +0,0 @@ -// Test quote nesting. - ---- -// Test quote selection. -#set page(width: auto) -#set text(lang: "en") -=== EN -#quote[An apostroph'] \ -#quote[A #quote[nested] quote] \ -#quote[A #quote[very #quote[nested]] quote] - -#set text(lang: "de") -=== DE -#quote[Satz mit Apostroph'] \ -#quote[Satz mit #quote[Zitat]] \ -#quote[A #quote[very #quote[nested]] quote] - -#set smartquote(alternative: true) -=== DE Alternative -#quote[Satz mit Apostroph'] \ -#quote[Satz mit #quote[Zitat]] \ -#quote[A #quote[very #quote[nested]] quote] - ---- -// With custom quotes. -#set smartquote(quotes: (single: ("<", ">"), double: ("(", ")"))) -#quote[A #quote[nested] quote] diff --git a/tests/typ/text/quote.typ b/tests/typ/text/quote.typ deleted file mode 100644 index 1573438c..00000000 --- a/tests/typ/text/quote.typ +++ /dev/null @@ -1,60 +0,0 @@ -// Test the quote element. - ---- -// Text direction affects author positioning -And I quote: #quote(attribution: [René Descartes])[cogito, ergo sum]. - -#set text(lang: "ar") -#quote(attribution: [عالم])[مرحبًا] - ---- -// Text direction affects block alignment -#set quote(block: true) -#quote(attribution: [René Descartes])[cogito, ergo sum] - -#set text(lang: "ar") -#quote(attribution: [عالم])[مرحبًا] - ---- -// Spacing with other blocks -#set quote(block: true) -#set text(8pt) - -#lorem(10) -#quote(lorem(10)) -#lorem(10) - ---- -// Inline citation -#set text(8pt) -#quote(attribution: <tolkien54>)[In a hole in the ground there lived a hobbit.] - -#set text(0pt) -#bibliography("/assets/bib/works.bib") - ---- -// Citation-format: label or numeric -#set text(8pt) -#set quote(block: true) -#quote(attribution: <tolkien54>)[In a hole in the ground there lived a hobbit.] - -#set text(0pt) -#bibliography("/assets/bib/works.bib", style: "ieee") - ---- -// Citation-format: note -#set text(8pt) -#set quote(block: true) -#quote(attribution: <tolkien54>)[In a hole in the ground there lived a hobbit.] - -#set text(0pt) -#bibliography("/assets/bib/works.bib", style: "chicago-notes") - ---- -// Citation-format: author-date or author -#set text(8pt) -#set quote(block: true) -#quote(attribution: <tolkien54>)[In a hole in the ground there lived a hobbit.] - -#set text(0pt) -#bibliography("/assets/bib/works.bib", style: "apa") diff --git a/tests/typ/text/quotes.typ b/tests/typ/text/quotes.typ deleted file mode 100644 index 3b4eb6ba..00000000 --- a/tests/typ/text/quotes.typ +++ /dev/null @@ -1,71 +0,0 @@ -// Test smart quotes. - ---- -#set page(width: 250pt) - -// Test simple quotations in various languages. -#set text(lang: "en") -"The horse eats no cucumber salad" was the first sentence ever uttered on the 'telephone.' - -#set text(lang: "de") -"Das Pferd frisst keinen Gurkensalat" war der erste jemals am 'Fernsprecher' gesagte Satz. - -#set text(lang: "de", region: "CH") -"Das Pferd frisst keinen Gurkensalat" war der erste jemals am 'Fernsprecher' gesagte Satz. - -#set text(lang: "es", region: none) -"El caballo no come ensalada de pepino" fue la primera frase pronunciada por 'teléfono'. - -#set text(lang: "es", region: "MX") -"El caballo no come ensalada de pepino" fue la primera frase pronunciada por 'teléfono'. - -#set text(lang: "fr", region: none) -"Le cheval ne mange pas de salade de concombres" est la première phrase jamais prononcée au 'téléphone'. - -#set text(lang: "fi") -"Hevonen ei syö kurkkusalaattia" oli ensimmäinen koskaan 'puhelimessa' lausuttu lause. - -#set text(lang: "gr") -"Το άλογο δεν τρώει αγγουροσαλάτα" ήταν η πρώτη πρόταση που ειπώθηκε στο 'τηλέφωνο'. - -#set text(lang: "he") -"הסוס לא אוכל סלט מלפפונים" היה המשפט ההראשון שנאמר ב 'טלפון'. - -#set text(lang: "ro") -"Calul nu mănâncă salată de castraveți" a fost prima propoziție rostită vreodată la 'telefon'. - -#set text(lang: "ru") -"Лошадь не ест салат из огурцов" - это была первая фраза, сказанная по 'телефону'. - ---- -// Test single pair of quotes. -"" - ---- -// Test sentences with numbers and apostrophes. -The 5'11" 'quick' brown fox jumps over the "lazy" dog's ear. - -He said "I'm a big fella." - ---- -// Test escape sequences. -The 5\'11\" 'quick\' brown fox jumps over the \"lazy" dog\'s ear. - ---- -// Test turning smart quotes off. -He's told some books contain questionable "example text". - -#set smartquote(enabled: false) -He's told some books contain questionable "example text". - ---- -// Test changing properties within text. -"She suddenly started speaking french: #text(lang: "fr")['Je suis une banane.']" Roman told me. - -Some people's thought on this would be #[#set smartquote(enabled: false); "strange."] - ---- -// Test nested double and single quotes. -"'test statement'" \ -"'test' statement" \ -"statement 'test'" diff --git a/tests/typ/text/raw-align.typ b/tests/typ/text/raw-align.typ deleted file mode 100644 index 1dbaad16..00000000 --- a/tests/typ/text/raw-align.typ +++ /dev/null @@ -1,37 +0,0 @@ -// Test the alignment of text inside of raw blocks. - ---- -// Text inside raw block should be unaffected by outer alignment by default. -#set align(center) -#set page(width: 180pt) -#set text(6pt) - -#lorem(20) - -```py -def something(x): - return x - -a = 342395823859823958329 -b = 324923 -``` - -#lorem(20) - ---- -// Text inside raw block should follow the specified alignment. -#set page(width: 180pt) -#set text(6pt) - -#lorem(20) -#align(center, raw( - lang: "typ", - block: true, - align: right, - "#let f(x) = x\n#align(center, line(length: 1em))", -)) -#lorem(20) - ---- -// Error: 17-20 expected `start`, `left`, `center`, `right`, or `end`, found top -#set raw(align: top) diff --git a/tests/typ/text/raw-code.typ b/tests/typ/text/raw-code.typ deleted file mode 100644 index 3ac72a05..00000000 --- a/tests/typ/text/raw-code.typ +++ /dev/null @@ -1,86 +0,0 @@ -// Test code highlighting. - ---- -#set page(width: 180pt) -#set text(6pt) -#show raw: it => rect( - width: 100%, - inset: (x: 4pt, y: 5pt), - radius: 4pt, - fill: rgb(239, 241, 243), - place(right, text(luma(110), it.lang)) + it, -) - -```typ -= Chapter 1 -#lorem(100) - -#let hi = "Hello World" -#show heading: emph -``` - -```rust -/// A carefully designed state machine. -#[derive(Debug)] -enum State<'a> { A(u8), B(&'a str) } - -fn advance(state: State<'_>) -> State<'_> { - unimplemented!("state machine") -} -``` - -```py -import this - -def hi(): - print("Hi!") -``` - -```cpp -#include <iostream> - -int main() { - std::cout << "Hello, world!"; -} -``` - -```julia -# Add two numbers -function add(x, y) - return x * y -end -``` - - // Try with some indent. - ```html - <!DOCTYPE html> - <html> - <head> - <meta charset="utf-8"> - </head> - <body> - <h1>Topic</h1> - <p>The Hypertext Markup Language.</p> - <script> - function foo(a, b) { - return a + b + "string"; - } - </script> - </body> - </html> - ``` - ---- -#set page(width: 180pt) -#set text(6pt) -#set raw(lang:"python") - -Inline raws, multiline e.g. `for i in range(10): - # Only this line is a comment. - print(i)` or otherwise e.g. `print(j)`, are colored properly. - -Inline raws, multiline e.g. ` -# Appears blocky due to linebreaks at the boundary. -for i in range(10): - print(i) -` or otherwise e.g. `print(j)`, are colored properly. diff --git a/tests/typ/text/raw-line.typ b/tests/typ/text/raw-line.typ deleted file mode 100644 index 19e64fac..00000000 --- a/tests/typ/text/raw-line.typ +++ /dev/null @@ -1,109 +0,0 @@ -// Test line in raw code. - ---- -#set page(width: 200pt) - -```rs -fn main() { - println!("Hello, world!"); -} -``` - -#show raw.line: it => { - box(stack( - dir: ltr, - box(width: 15pt)[#it.number], - it.body, - )) - linebreak() -} - -```rs -fn main() { - println!("Hello, world!"); -} -``` - ---- -#set page(width: 200pt) -#show raw: it => stack(dir: ttb, ..it.lines) -#show raw.line: it => { - box( - width: 100%, - height: 1.75em, - inset: 0.25em, - fill: if calc.rem(it.number, 2) == 0 { - luma(90%) - } else { - white - }, - align(horizon, stack( - dir: ltr, - box(width: 15pt)[#it.number], - it.body, - )) - ) -} - -```typ -#show raw.line: block.with( - fill: luma(60%) -); - -Hello, world! - -= A heading for good measure -``` - ---- -#set page(width: 200pt) -#show raw.line: set text(fill: red) - -```py -import numpy as np - -def f(x): - return x**2 - -x = np.linspace(0, 10, 100) -y = f(x) - -print(x) -print(y) -``` - ---- -// Ref: false - -// Test line extraction works. - -#show raw: code => { - for i in code.lines { - test(i.count, 10) - } - - test(code.lines.at(0).text, "import numpy as np") - test(code.lines.at(1).text, "") - test(code.lines.at(2).text, "def f(x):") - test(code.lines.at(3).text, " return x**2") - test(code.lines.at(4).text, "") - test(code.lines.at(5).text, "x = np.linspace(0, 10, 100)") - test(code.lines.at(6).text, "y = f(x)") - test(code.lines.at(7).text, "") - test(code.lines.at(8).text, "print(x)") - test(code.lines.at(9).text, "print(y)") - test(code.lines.at(10, default: none), none) -} - -```py -import numpy as np - -def f(x): - return x**2 - -x = np.linspace(0, 10, 100) -y = f(x) - -print(x) -print(y) -``` diff --git a/tests/typ/text/raw-syntaxes.typ b/tests/typ/text/raw-syntaxes.typ deleted file mode 100644 index e6c46924..00000000 --- a/tests/typ/text/raw-syntaxes.typ +++ /dev/null @@ -1,14 +0,0 @@ -// Test code highlighting with custom syntaxes. - ---- -#set page(width: 180pt) -#set text(6pt) -#set raw(syntaxes: "/assets/syntaxes/SExpressions.sublime-syntax") - -```sexp -(defun factorial (x) - (if (zerop x) - ; with a comment - 1 - (* x (factorial (- x 1))))) -``` diff --git a/tests/typ/text/raw-tabs.typ b/tests/typ/text/raw-tabs.typ deleted file mode 100644 index d31326c0..00000000 --- a/tests/typ/text/raw-tabs.typ +++ /dev/null @@ -1,11 +0,0 @@ -// Test tabs in raw code. - ---- -#set raw(tab-size: 8) - -```tsv -Year Month Day -2000 2 3 -2001 2 1 -2002 3 10 -``` diff --git a/tests/typ/text/raw-theme.typ b/tests/typ/text/raw-theme.typ deleted file mode 100644 index d6cda221..00000000 --- a/tests/typ/text/raw-theme.typ +++ /dev/null @@ -1,24 +0,0 @@ -// Test code highlighting with custom theme. - ---- -#set page(width: 180pt) -#set text(6pt) -#set raw(theme: "/assets/themes/halcyon.tmTheme") -#show raw: it => { - set text(fill: rgb("a2aabc")) - rect( - width: 100%, - inset: (x: 4pt, y: 5pt), - radius: 4pt, - fill: rgb("1d2433"), - place(right, text(luma(240), it.lang)) + it, - ) -} - -```typ -= Chapter 1 -#lorem(100) - -#let hi = "Hello World" -#show heading: emph -``` diff --git a/tests/typ/text/raw.typ b/tests/typ/text/raw.typ deleted file mode 100644 index 525988ec..00000000 --- a/tests/typ/text/raw.typ +++ /dev/null @@ -1,79 +0,0 @@ -// Test raw blocks. - ---- -// No extra space. -`A``B` - ---- -// Empty raw block. -Empty raw block:``. - ---- -// Typst syntax inside. -```typ #let x = 1``` \ -```typ #f(1)``` - ---- -// Multiline block splits paragraphs. - -Text -```rust -fn code() {} -``` -Text - ---- -// Lots of backticks inside. -```` -```backticks``` -```` - ---- -// Trimming. - -// Space between "rust" and "let" is trimmed. -The keyword ```rust let```. - -// Trimming depends on number backticks. -(``) \ -(` untrimmed `) \ -(``` trimmed` ```) \ -(``` trimmed ```) \ -(``` trimmed```) \ - ---- -// Single ticks should not have a language. -`rust let` - ---- -// First line is not dedented and leading space is still possible. - ``` A - B - C - ``` - ---- -// Do not take empty lines into account when computing dedent. -``` - A - - B -``` - ---- -// Take last line into account when computing dedent. -``` - A - - B - ``` - ---- -// Text show rule -#show raw: set text(font: "Roboto") -`Roboto` - ---- -// Unterminated. -// Error: 1-2:1 unclosed raw text -`endless diff --git a/tests/typ/text/shaping.typ b/tests/typ/text/shaping.typ deleted file mode 100644 index 4a2b4f1e..00000000 --- a/tests/typ/text/shaping.typ +++ /dev/null @@ -1,29 +0,0 @@ -// Test shaping quirks. - ---- -// Test separation by script. -#set text(font: ("Linux Libertine", "IBM Plex Sans Devanagari")) -ABCअपार्टमेंट - -// This is how it should look like. -अपार्टमेंट - -// This (without the spaces) is how it would look -// if we didn't separate by script. -अ पा र् ट में ट - ---- -// A forced `latn` script inhibits Devanagari font features. -#set text(font: ("Linux Libertine", "IBM Plex Sans Devanagari"), script: "latn") -ABCअपार्टमेंट - ---- -// A forced `deva` script enables Devanagari font features. -#set text(font: ("Linux Libertine", "IBM Plex Sans Devanagari"), script: "deva") -ABCअपार्टमेंट - ---- -// Test that RTL safe-to-break doesn't panic even though newline -// doesn't exist in shaping output. -#set text(dir: rtl, font: "Noto Serif Hebrew") -\ ט diff --git a/tests/typ/text/shift.typ b/tests/typ/text/shift.typ deleted file mode 100644 index 2b1b8984..00000000 --- a/tests/typ/text/shift.typ +++ /dev/null @@ -1,19 +0,0 @@ -// Test sub- and superscipt shifts. - ---- -#table( - columns: 3, - [Typo.], [Fallb.], [Synth], - [x#super[1]], [x#super[5n]], [x#super[2 #box(square(size: 6pt))]], - [x#sub[1]], [x#sub[5n]], [x#sub[2 #box(square(size: 6pt))]], -) - ---- -#set super(typographic: false, baseline: -0.25em, size: 0.7em) -n#super[1], n#sub[2], ... n#super[N] - ---- -#set underline(stroke: 0.5pt, offset: 0.15em) -#underline[The claim#super[\[4\]]] has been disputed. \ -The claim#super[#underline[\[4\]]] has been disputed. \ -It really has been#super(box(text(baseline: 0pt, underline[\[4\]]))) \ diff --git a/tests/typ/text/smartquotes.typ b/tests/typ/text/smartquotes.typ deleted file mode 100644 index da31866e..00000000 --- a/tests/typ/text/smartquotes.typ +++ /dev/null @@ -1,29 +0,0 @@ -// Test setting custom smartquotes - ---- -// Use language quotes for missing keys, allow partial reset -#set smartquote(quotes: "«»") -"Double and 'Single' Quotes" - -#set smartquote(quotes: (double: auto, single: "«»")) -"Double and 'Single' Quotes" - ---- -// Allow 2 graphemes -#set smartquote(quotes: "a\u{0301}a\u{0301}") -"Double and 'Single' Quotes" - -#set smartquote(quotes: (single: "a\u{0301}a\u{0301}")) -"Double and 'Single' Quotes" - ---- -// Error: 25-28 expected 2 characters, found 1 character -#set smartquote(quotes: "'") - ---- -// Error: 25-35 expected 2 quotes, found 4 quotes -#set smartquote(quotes: ("'",) * 4) - ---- -// Error: 25-45 expected 2 quotes, found 4 quotes -#set smartquote(quotes: (single: ("'",) * 4)) diff --git a/tests/typ/text/space.typ b/tests/typ/text/space.typ deleted file mode 100644 index 9d29f347..00000000 --- a/tests/typ/text/space.typ +++ /dev/null @@ -1,53 +0,0 @@ -// Test whitespace handling. - ---- -// Spacing around code constructs. -A#let x = 1;B #test(x, 1) \ -C #let x = 2;D #test(x, 2) \ -E#if true [F]G \ -H #if true{"I"} J \ -K #if true [L] else []M \ -#let c = true; N#while c [#(c = false)O] P \ -#let c = true; Q #while c { c = false; "R" } S \ -T#for _ in (none,) {"U"}V -#let foo = "A" ; \ -#foo;B \ -#foo; B \ -#foo ;B - ---- -// Test spacing with comments. -A/**/B/**/C \ -A /**/ B/**/C \ -A /**/B/**/ C - ---- -// Test that a run consisting only of whitespace isn't trimmed. -A#text(font: "IBM Plex Serif")[ ]B - ---- -// Test font change after space. -Left #text(font: "IBM Plex Serif")[Right]. - ---- -// Test that linebreak consumed surrounding spaces. -#align(center)[A \ B \ C] - ---- -// Test that space at start of non-backslash-linebreak line isn't trimmed. -A#"\n" B - ---- -// Test that trailing space does not force a line break. -LLLLLLLLLLLLLLLLLL R _L_ - ---- -// Test that ideographic spaces are preserved. -#set text(lang: "ja", font: "Noto Serif CJK JP") - -だろうか? 何のために! 私は、 - ---- -// Test that thin spaces are preserved. -| | U+0020 regular space \ -| | U+2009 thin space diff --git a/tests/typ/text/stroke.typ b/tests/typ/text/stroke.typ deleted file mode 100644 index 713bbe2f..00000000 --- a/tests/typ/text/stroke.typ +++ /dev/null @@ -1,21 +0,0 @@ -#set text(size: 20pt) -#set page(width: auto) -测试字体 #lorem(5) - -#text(stroke: 0.3pt + red)[测试字体#lorem(5)] - -#text(stroke: 0.5pt + red)[测试字体#lorem(5)] - -#text(stroke: 0.7pt + red)[测试字体#lorem(5)] - -#text(stroke: 1pt + red)[测试字体#lorem(5)] - -#text(stroke: 2pt + red)[测试字体#lorem(5)] - -#text(stroke: 5pt + red)[测试字体#lorem(5)] - -#text(stroke: 7pt + red)[测试字体#lorem(5)] - -#text(stroke: (paint: blue, thickness: 1pt, dash: "dashed"))[测试字体#lorem(5)] - -#text(stroke: 1pt + gradient.linear(..color.map.rainbow))[测试字体#lorem(5)] // gradient doesn't work now diff --git a/tests/typ/text/symbol.typ b/tests/typ/text/symbol.typ deleted file mode 100644 index f7179449..00000000 --- a/tests/typ/text/symbol.typ +++ /dev/null @@ -1,18 +0,0 @@ -// Test symbols. - ---- -#emoji.face -#emoji.woman.old -#emoji.turtle - -#set text(font: "New Computer Modern Math") -#sym.arrow -#sym.arrow.l -#sym.arrow.r.squiggly -#sym.arrow.tr.hook - -#sym.arrow.r;this and this#sym.arrow.l; - ---- -// Error: 13-20 unknown symbol modifier -#emoji.face.garbage diff --git a/tests/typ/text/tracking-spacing.typ b/tests/typ/text/tracking-spacing.typ deleted file mode 100644 index a89b991f..00000000 --- a/tests/typ/text/tracking-spacing.typ +++ /dev/null @@ -1,31 +0,0 @@ -// Test tracking characters apart or together. - ---- -// Test tracking. -#set text(tracking: -0.01em) -I saw Zoe yӛsterday, on the tram. - ---- -// Test tracking for only part of paragraph. -I'm in#text(tracking: 0.15em + 1.5pt)[ spaace]! - ---- -// Test that tracking doesn't disrupt mark placement. -#set text(font: ("PT Sans", "Noto Serif Hebrew")) -#set text(tracking: 0.3em) -טֶקסט - ---- -// Test tracking in arabic text (makes no sense whatsoever) -#set text(tracking: 0.3em) -النص - ---- -// Test word spacing. -#set text(spacing: 1em) -My text has spaces. - ---- -// Test word spacing relative to the font's space width. -#set text(spacing: 50% + 1pt) -This is tight. diff --git a/tests/typ/visualize/gradient-conic.typ b/tests/typ/visualize/gradient-conic.typ deleted file mode 100644 index 83fdb07c..00000000 --- a/tests/typ/visualize/gradient-conic.typ +++ /dev/null @@ -1,25 +0,0 @@ -// Test conic gradients - ---- -#square( - size: 50pt, - fill: gradient.conic(..color.map.rainbow, space: color.hsv), -) - ---- -#square( - size: 50pt, - fill: gradient.conic(..color.map.rainbow, space: color.hsv, center: (10%, 10%)), -) - ---- -#square( - size: 50pt, - fill: gradient.conic(..color.map.rainbow, space: color.hsv, center: (90%, 90%)), -) - ---- -#square( - size: 50pt, - fill: gradient.conic(..color.map.rainbow, space: color.hsv, angle: 90deg), -) diff --git a/tests/typ/visualize/gradient-dir.typ b/tests/typ/visualize/gradient-dir.typ deleted file mode 100644 index 92e00393..00000000 --- a/tests/typ/visualize/gradient-dir.typ +++ /dev/null @@ -1,13 +0,0 @@ -// Test gradients with direction. - ---- -#set page(width: 900pt) -#for i in range(0, 360, step: 15){ - box( - height: 100pt, - width: 100pt, - fill: gradient.linear(angle: i * 1deg, (red, 0%), (blue, 100%)), - align(center + horizon)[Angle: #i degrees], - ) - h(30pt) -} diff --git a/tests/typ/visualize/gradient-hue-rotation.typ b/tests/typ/visualize/gradient-hue-rotation.typ deleted file mode 100644 index 2cc6f9a6..00000000 --- a/tests/typ/visualize/gradient-hue-rotation.typ +++ /dev/null @@ -1,66 +0,0 @@ -// Tests whether hue rotation works correctly. - ---- -// Test in Oklab space for reference. -#set page( - width: 100pt, - height: 30pt, - fill: gradient.linear(red, purple, space: oklab) -) - ---- -// Test in OkLCH space. -#set page( - width: 100pt, - height: 30pt, - fill: gradient.linear(red, purple, space: oklch) -) - ---- -// Test in HSV space. -#set page( - width: 100pt, - height: 30pt, - fill: gradient.linear(red, purple, space: color.hsv) -) - ---- -// Test in HSL space. -#set page( - width: 100pt, - height: 30pt, - fill: gradient.linear(red, purple, space: color.hsl) -) - - ---- -// Test in Oklab space for reference. -#set page( - width: 100pt, - height: 100pt, - fill: gradient.conic(red, purple, space: oklab) -) - ---- -// Test in OkLCH space. -#set page( - width: 100pt, - height: 100pt, - fill: gradient.conic(red, purple, space: oklch) -) - ---- -// Test in HSV space. -#set page( - width: 100pt, - height: 100pt, - fill: gradient.conic(red, purple, space: color.hsv) -) - ---- -// Test in HSL space. -#set page( - width: 100pt, - height: 100pt, - fill: gradient.conic(red, purple, space: color.hsl) -) diff --git a/tests/typ/visualize/gradient-math.typ b/tests/typ/visualize/gradient-math.typ deleted file mode 100644 index f16e5c58..00000000 --- a/tests/typ/visualize/gradient-math.typ +++ /dev/null @@ -1,89 +0,0 @@ -// Test that gradients are applied correctly on equations. - ---- -// Test on cancel -#show math.equation: set text(fill: gradient.linear(..color.map.rainbow)) -#show math.equation: box - -$ a dot cancel(5) = cancel(25) 5 x + cancel(5) 1 $ - ---- -// Test on frac -#show math.equation: set text(fill: gradient.linear(..color.map.rainbow)) -#show math.equation: box - -$ nabla dot bold(E) = frac(rho, epsilon_0) $ - ---- -// Test on root -#show math.equation: set text(fill: gradient.linear(..color.map.rainbow)) -#show math.equation: box - -$ x_"1,2" = frac(-b +- sqrt(b^2 - 4 a c), 2 a) $ - ---- -// Test on matrix -#show math.equation: set text(fill: gradient.linear(..color.map.rainbow)) -#show math.equation: box - -$ A = mat( - 1, 2, 3; - 4, 5, 6; - 7, 8, 9 -) $ - ---- -// Test on underover -#show math.equation: set text(fill: gradient.linear(..color.map.rainbow)) -#show math.equation: box - -$ underline(X^2) $ -$ overline("hello, world!") $ - ---- -// Test a different direction -#show math.equation: set text(fill: gradient.linear(..color.map.rainbow, dir: ttb)) -#show math.equation: box - -$ A = mat( - 1, 2, 3; - 4, 5, 6; - 7, 8, 9 -) $ - -$ x_"1,2" = frac(-b +- sqrt(b^2 - 4 a c), 2 a) $ - ---- -// Test miscellaneous -#show math.equation: set text(fill: gradient.linear(..color.map.rainbow)) -#show math.equation: box - -$ hat(x) = bar x bar = vec(x, y, z) = tilde(x) = dot(x) $ -$ x prime = vec(1, 2, delim: "[") $ -$ sum_(i in NN) 1 + i $ -$ attach( - Pi, t: alpha, b: beta, - tl: 1, tr: 2+3, bl: 4+5, br: 6, -) $ - ---- -// Test radial gradient -#show math.equation: set text(fill: gradient.radial(..color.map.rainbow, center: (30%, 30%))) -#show math.equation: box - -$ A = mat( - 1, 2, 3; - 4, 5, 6; - 7, 8, 9 -) $ - ---- -// Test conic gradient -#show math.equation: set text(fill: gradient.conic(red, blue, angle: 45deg)) -#show math.equation: box - -$ A = mat( - 1, 2, 3; - 4, 5, 6; - 7, 8, 9 -) $ diff --git a/tests/typ/visualize/gradient-presets.typ b/tests/typ/visualize/gradient-presets.typ deleted file mode 100644 index ca1a7007..00000000 --- a/tests/typ/visualize/gradient-presets.typ +++ /dev/null @@ -1,33 +0,0 @@ -// Test all gradient presets. - ---- -#set page(width: 200pt, height: auto, margin: 0pt) -#set text(fill: white, size: 18pt) -#set text(top-edge: "bounds", bottom-edge: "bounds") - -#let presets = ( - ("turbo", color.map.turbo), - ("cividis", color.map.cividis), - ("rainbow", color.map.rainbow), - ("spectral", color.map.spectral), - ("viridis", color.map.viridis), - ("inferno", color.map.inferno), - ("magma", color.map.magma), - ("plasma", color.map.plasma), - ("rocket", color.map.rocket), - ("mako", color.map.mako), - ("vlag", color.map.vlag), - ("icefire", color.map.icefire), - ("flare", color.map.flare), - ("crest", color.map.crest), -) - -#stack( - spacing: 3pt, - ..presets.map(((name, preset)) => block( - width: 100%, - height: 20pt, - fill: gradient.linear(..preset), - align(center + horizon, smallcaps(name)), - )) -) diff --git a/tests/typ/visualize/gradient-radial.typ b/tests/typ/visualize/gradient-radial.typ deleted file mode 100644 index c0d1b249..00000000 --- a/tests/typ/visualize/gradient-radial.typ +++ /dev/null @@ -1,49 +0,0 @@ -// Test the different radial gradient features. ---- - -#square( - size: 100pt, - fill: gradient.radial(..color.map.rainbow, space: color.hsl), -) ---- - -#grid( - columns: 2, - square( - size: 50pt, - fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (0%, 0%)), - ), - square( - size: 50pt, - fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (0%, 100%)), - ), - square( - size: 50pt, - fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (100%, 0%)), - ), - square( - size: 50pt, - fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (100%, 100%)), - ), -) - ---- - -#square( - size: 50pt, - fill: gradient.radial(..color.map.rainbow, space: color.hsl, radius: 10%), -) -#square( - size: 50pt, - fill: gradient.radial(..color.map.rainbow, space: color.hsl, radius: 72%), -) - ---- -#circle( - radius: 25pt, - fill: gradient.radial(white, rgb("#8fbc8f"), focal-center: (35%, 35%), focal-radius: 5%), -) -#circle( - radius: 25pt, - fill: gradient.radial(white, rgb("#8fbc8f"), focal-center: (75%, 35%), focal-radius: 5%), -) diff --git a/tests/typ/visualize/gradient-relative-conic.typ b/tests/typ/visualize/gradient-relative-conic.typ deleted file mode 100644 index 26b509af..00000000 --- a/tests/typ/visualize/gradient-relative-conic.typ +++ /dev/null @@ -1,29 +0,0 @@ -// Test whether `relative: "parent"` works correctly on conic gradients. - ---- -// The image should look as if there is a single gradient that is being used for -// both the page and the rectangles. -#let grad = gradient.conic(red, blue, green, purple, relative: "parent"); -#let my-rect = rect(width: 50%, height: 50%, fill: grad) -#set page( - height: 200pt, - width: 200pt, - fill: grad, - background: place(top + left, my-rect), -) -#place(top + right, my-rect) -#place(bottom + center, rotate(45deg, my-rect)) - ---- -// The image should look as if there are multiple gradients, one for each -// rectangle. -#let grad = gradient.conic(red, blue, green, purple, relative: "self"); -#let my-rect = rect(width: 50%, height: 50%, fill: grad) -#set page( - height: 200pt, - width: 200pt, - fill: grad, - background: place(top + left, my-rect), -) -#place(top + right, my-rect) -#place(bottom + center, rotate(45deg, my-rect)) diff --git a/tests/typ/visualize/gradient-relative-linear.typ b/tests/typ/visualize/gradient-relative-linear.typ deleted file mode 100644 index 8e1d04dc..00000000 --- a/tests/typ/visualize/gradient-relative-linear.typ +++ /dev/null @@ -1,29 +0,0 @@ -// Test whether `relative: "parent"` works correctly on linear gradients. - ---- -// The image should look as if there is a single gradient that is being used for -// both the page and the rectangles. -#let grad = gradient.linear(red, blue, green, purple, relative: "parent"); -#let my-rect = rect(width: 50%, height: 50%, fill: grad) -#set page( - height: 200pt, - width: 200pt, - fill: grad, - background: place(top + left, my-rect), -) -#place(top + right, my-rect) -#place(bottom + center, rotate(45deg, my-rect)) - ---- -// The image should look as if there are multiple gradients, one for each -// rectangle. -#let grad = gradient.linear(red, blue, green, purple, relative: "self"); -#let my-rect = rect(width: 50%, height: 50%, fill: grad) -#set page( - height: 200pt, - width: 200pt, - fill: grad, - background: place(top + left, my-rect), -) -#place(top + right, my-rect) -#place(bottom + center, rotate(45deg, my-rect)) diff --git a/tests/typ/visualize/gradient-relative-radial.typ b/tests/typ/visualize/gradient-relative-radial.typ deleted file mode 100644 index 87686896..00000000 --- a/tests/typ/visualize/gradient-relative-radial.typ +++ /dev/null @@ -1,29 +0,0 @@ -// Test whether `relative: "parent"` works correctly on radial gradients. - ---- -// The image should look as if there is a single gradient that is being used for -// both the page and the rectangles. -#let grad = gradient.radial(red, blue, green, purple, relative: "parent"); -#let my-rect = rect(width: 50%, height: 50%, fill: grad) -#set page( - height: 200pt, - width: 200pt, - fill: grad, - background: place(top + left, my-rect), -) -#place(top + right, my-rect) -#place(bottom + center, rotate(45deg, my-rect)) - ---- -// The image should look as if there are multiple gradients, one for each -// rectangle. -#let grad = gradient.radial(red, blue, green, purple, relative: "self"); -#let my-rect = rect(width: 50%, height: 50%, fill: grad) -#set page( - height: 200pt, - width: 200pt, - fill: grad, - background: place(top + left, my-rect), -) -#place(top + right, my-rect) -#place(bottom + center, rotate(45deg, my-rect)) diff --git a/tests/typ/visualize/gradient-repeat.typ b/tests/typ/visualize/gradient-repeat.typ deleted file mode 100644 index fd4ea279..00000000 --- a/tests/typ/visualize/gradient-repeat.typ +++ /dev/null @@ -1,36 +0,0 @@ -// Test repeated gradients. - ---- -#rect( - height: 40pt, - width: 100%, - fill: gradient.linear(..color.map.inferno).repeat(2, mirror: true) -) - ---- -#rect( - height: 40pt, - width: 100%, - fill: gradient.linear(..color.map.rainbow).repeat(2, mirror: true), -) - ---- -#rect( - height: 40pt, - width: 100%, - fill: gradient.linear(..color.map.rainbow).repeat(5, mirror: true) -) - ---- -#rect( - height: 40pt, - width: 100%, - fill: gradient.linear(..color.map.rainbow).sharp(10).repeat(5, mirror: false) -) - ---- -#rect( - height: 40pt, - width: 100%, - fill: gradient.linear(..color.map.rainbow).sharp(10).repeat(5, mirror: true) -) diff --git a/tests/typ/visualize/gradient-sharp.typ b/tests/typ/visualize/gradient-sharp.typ deleted file mode 100644 index 89841efd..00000000 --- a/tests/typ/visualize/gradient-sharp.typ +++ /dev/null @@ -1,29 +0,0 @@ -// Test sharp gradients. - ---- -#square( - size: 100pt, - fill: gradient.linear(..color.map.rainbow, space: color.hsl).sharp(10), -) -#square( - size: 100pt, - fill: gradient.radial(..color.map.rainbow, space: color.hsl).sharp(10), -) -#square( - size: 100pt, - fill: gradient.conic(..color.map.rainbow, space: color.hsl).sharp(10), -) - ---- -#square( - size: 100pt, - fill: gradient.linear(..color.map.rainbow, space: color.hsl).sharp(10, smoothness: 40%), -) -#square( - size: 100pt, - fill: gradient.radial(..color.map.rainbow, space: color.hsl).sharp(10, smoothness: 40%), -) -#square( - size: 100pt, - fill: gradient.conic(..color.map.rainbow, space: color.hsl).sharp(10, smoothness: 40%), -) diff --git a/tests/typ/visualize/gradient-stroke.typ b/tests/typ/visualize/gradient-stroke.typ deleted file mode 100644 index d4461497..00000000 --- a/tests/typ/visualize/gradient-stroke.typ +++ /dev/null @@ -1,31 +0,0 @@ -// Test gradients on strokes. - ---- -#align(center + top, square(size: 50pt, fill: black, stroke: 5pt + gradient.linear(red, blue))) - ---- -#align( - center + bottom, - square( - size: 50pt, - fill: gradient.radial(red, blue, radius: 70.7%, focal-center: (10%, 10%)), - stroke: 10pt + gradient.radial(red, blue, radius: 70.7%, focal-center: (10%, 10%)) - ) -) - ---- -#align( - center + bottom, - square( - size: 50pt, - fill: black, - stroke: 10pt + gradient.conic(red, blue) - ) -) - ---- -// Test gradient on lines -#set page(width: 100pt, height: 100pt) -#line(length: 100%, stroke: 1pt + gradient.linear(red, blue)) -#line(length: 100%, angle: 10deg, stroke: 1pt + gradient.linear(red, blue)) -#line(length: 100%, angle: 10deg, stroke: 1pt + gradient.linear(red, blue, relative: "parent")) diff --git a/tests/typ/visualize/gradient-text-decorations.typ b/tests/typ/visualize/gradient-text-decorations.typ deleted file mode 100644 index a4e861d8..00000000 --- a/tests/typ/visualize/gradient-text-decorations.typ +++ /dev/null @@ -1,9 +0,0 @@ -// Tests gradients on text decorations. - ---- - -#set text(fill: gradient.linear(red, blue)) - -Hello #underline[World]! \ -Hello #overline[World]! \ -Hello #strike[World]! \ diff --git a/tests/typ/visualize/gradient-text-other.typ b/tests/typ/visualize/gradient-text-other.typ deleted file mode 100644 index 04b84cb6..00000000 --- a/tests/typ/visualize/gradient-text-other.typ +++ /dev/null @@ -1,14 +0,0 @@ -// Test text gradients with radial and conic gradients. - ---- -#set page(width: 200pt, height: auto, margin: 10pt) -#set par(justify: true) -#set text(fill: gradient.radial(red, blue)) -#lorem(30) - - ---- -#set page(width: 200pt, height: auto, margin: 10pt) -#set par(justify: true) -#set text(fill: gradient.conic(red, blue, angle: 45deg)) -#lorem(30) diff --git a/tests/typ/visualize/gradient-text.typ b/tests/typ/visualize/gradient-text.typ deleted file mode 100644 index 671172e1..00000000 --- a/tests/typ/visualize/gradient-text.typ +++ /dev/null @@ -1,49 +0,0 @@ -// Test that gradient fills on text. -// The solid bar gradients are used to make sure that all transforms are -// correct: if you can see the text through the bar, then the gradient is -// misaligned to its reference container. -// Ref: true - ---- -// Ref: false -// Make sure they don't work when `relative: "self"`. - -// Hint: 17-61 make sure to set `relative: auto` on your text fill -// Error: 17-61 gradients and patterns on text must be relative to the parent -#set text(fill: gradient.linear(red, blue, relative: "self")) - ---- -// Test that gradient fills on text work for globally defined gradients. - -#set page(width: 200pt, height: auto, margin: 10pt, background: { - rect(width: 100%, height: 30pt, fill: gradient.linear(red, blue)) -}) -#set par(justify: true) -#set text(fill: gradient.linear(red, blue)) -#lorem(30) - ---- -// Sanity check that the direction works on text. - -#set page(width: 200pt, height: auto, margin: 10pt, background: { - rect(height: 100%, width: 30pt, fill: gradient.linear(dir: btt, red, blue)) -}) -#set par(justify: true) -#set text(fill: gradient.linear(dir: btt, red, blue)) -#lorem(30) - ---- -// Test that gradient fills on text work for locally defined gradients. - -#set page(width: auto, height: auto, margin: 10pt) -#show box: set text(fill: gradient.linear(..color.map.rainbow)) - -Hello, #box[World]! - ---- -// Test that gradients fills on text work with transforms. - -#set page(width: auto, height: auto, margin: 10pt) -#show box: set text(fill: gradient.linear(..color.map.rainbow)) - -#rotate(45deg, box[World]) diff --git a/tests/typ/visualize/gradient-transform.typ b/tests/typ/visualize/gradient-transform.typ deleted file mode 100644 index d33c4ac2..00000000 --- a/tests/typ/visualize/gradient-transform.typ +++ /dev/null @@ -1,12 +0,0 @@ -// Test whether gradients work well when they are contained within a transform. - ---- -#let grad = gradient.linear(red, blue, green, purple, relative: "parent"); -#let my-rect = rect(width: 50pt, height: 50pt, fill: grad) -#set page( - height: 200pt, - width: 200pt, -) -#place(top + right, scale(x: 200%, y: 130%, my-rect)) -#place(bottom + center, rotate(45deg, my-rect)) -#place(horizon + center, scale(x: 200%, y: 130%, rotate(45deg, my-rect))) diff --git a/tests/typ/visualize/image-scale.typ b/tests/typ/visualize/image-scale.typ deleted file mode 100644 index 7ddf435e..00000000 --- a/tests/typ/visualize/image-scale.typ +++ /dev/null @@ -1,6 +0,0 @@ -// Test that images aren't upscaled. - ---- -// Image is just 48x80 at 220dpi. It should not be scaled to fit the page -// width, but rather max out at its natural size. -#image("/assets/images/f2t.jpg") diff --git a/tests/typ/visualize/image.typ b/tests/typ/visualize/image.typ deleted file mode 100644 index a7965b2d..00000000 --- a/tests/typ/visualize/image.typ +++ /dev/null @@ -1,82 +0,0 @@ -// Test the `image` function. - ---- -// Test loading different image formats. - -// Load an RGBA PNG image. -#image("/assets/images/rhino.png") - -// Load an RGB JPEG image. -#set page(height: 60pt) -#image("../../assets/images/tiger.jpg") - ---- -// Test configuring the size and fitting behaviour of images. - -// Set width and height explicitly. -#box(image("/assets/images/rhino.png", width: 30pt)) -#box(image("/assets/images/rhino.png", height: 30pt)) - -// Set width and height explicitly and force stretching. -#image("/assets/images/monkey.svg", width: 100%, height: 20pt, fit: "stretch") - -// Make sure the bounding-box of the image is correct. -#align(bottom + right, image("/assets/images/tiger.jpg", width: 40pt, alt: "A tiger")) - ---- -// Test all three fit modes. -#set page(height: 50pt, margin: 0pt) -#grid( - columns: (1fr, 1fr, 1fr), - rows: 100%, - gutter: 3pt, - image("/assets/images/tiger.jpg", width: 100%, height: 100%, fit: "contain"), - image("/assets/images/tiger.jpg", width: 100%, height: 100%, fit: "cover"), - image("/assets/images/monkey.svg", width: 100%, height: 100%, fit: "stretch"), -) - ---- -// Does not fit to remaining height of page. -#set page(height: 60pt) -Stuff -#image("/assets/images/rhino.png") - ---- -// Test baseline. -A #box(image("/assets/images/tiger.jpg", height: 1cm, width: 80%)) B - ---- -// Test advanced SVG features. -#image("/assets/images/pattern.svg") - ---- -// Error: 8-29 file not found (searched at typ/visualize/path/does/not/exist) -#image("path/does/not/exist") - ---- -// Error: 2-22 unknown image format -#image("./image.typ") - ---- -// Error: 2-33 failed to parse SVG (found closing tag 'g' instead of 'style' in line 4) -#image("/assets/images/bad.svg") - ---- -// Test parsing from svg data -#image.decode(`<svg xmlns="http://www.w3.org/2000/svg" height="140" width="500"><ellipse cx="200" cy="80" rx="100" ry="50" style="fill:yellow;stroke:purple;stroke-width:2" /></svg>`.text, format: "svg") - ---- -// Error: 2-168 failed to parse SVG (missing root node) -#image.decode(`<svg height="140" width="500"><ellipse cx="200" cy="80" rx="100" ry="50" style="fill:yellow;stroke:purple;stroke-width:2" /></svg>`.text, format: "svg") - ---- -// Test format auto detect -#image.decode(read("/assets/images/tiger.jpg", encoding: none), width: 80%) - ---- -// Test format manual -#image.decode(read("/assets/images/tiger.jpg", encoding: none), format: "jpg", width: 80%) - ---- -// Error: 2-91 failed to decode image (Format error decoding Png: Invalid PNG signature.) -#image.decode(read("/assets/images/tiger.jpg", encoding: none), format: "png", width: 80%) diff --git a/tests/typ/visualize/line.typ b/tests/typ/visualize/line.typ deleted file mode 100644 index 8c405932..00000000 --- a/tests/typ/visualize/line.typ +++ /dev/null @@ -1,51 +0,0 @@ -// Test lines. - ---- -#set page(height: 60pt) -#box({ - set line(stroke: 0.75pt) - place(line(end: (0.4em, 0pt))) - place(line(start: (0pt, 0.4em), end: (0pt, 0pt))) - line(end: (0.6em, 0.6em)) -}) Hello #box(line(length: 1cm))! - -#line(end: (70%, 50%)) - ---- -// Test the angle argument and positioning. - -#set page(fill: rgb("0B1026")) -#set line(stroke: white) - -#let star(size, ..args) = box(width: size, height: size)[ - #set text(spacing: 0%) - #set line(..args) - #set align(left) - #v(30%) - #place(line(length: +30%, start: (09.0%, 02%))) - #place(line(length: +30%, start: (38.7%, 02%), angle: -72deg)) - #place(line(length: +30%, start: (57.5%, 02%), angle: 252deg)) - #place(line(length: +30%, start: (57.3%, 02%))) - #place(line(length: -30%, start: (88.0%, 02%), angle: -36deg)) - #place(line(length: +30%, start: (73.3%, 48%), angle: 252deg)) - #place(line(length: -30%, start: (73.5%, 48%), angle: 36deg)) - #place(line(length: +30%, start: (25.4%, 48%), angle: -36deg)) - #place(line(length: +30%, start: (25.6%, 48%), angle: -72deg)) - #place(line(length: +32%, start: (8.50%, 02%), angle: 34deg)) -] - -#align(center, grid( - columns: 3, - column-gutter: 10pt, - ..((star(20pt, stroke: 0.5pt),) * 9) -)) - ---- -// Test errors. - -// Error: 12-19 point array must contain exactly two entries -#line(end: (50pt,)) - ---- -// Error: 14-26 expected relative length, found angle -#line(start: (3deg, 10pt), length: 5cm) diff --git a/tests/typ/visualize/path.typ b/tests/typ/visualize/path.typ deleted file mode 100644 index d475811f..00000000 --- a/tests/typ/visualize/path.typ +++ /dev/null @@ -1,52 +0,0 @@ -// Test paths. - ---- -#set page(height: 200pt, width: 200pt) -#table( - columns: (1fr, 1fr), - rows: (1fr, 1fr), - align: center + horizon, - path( - fill: red, - closed: true, - ((0%, 0%), (4%, -4%)), - ((50%, 50%), (4%, -4%)), - ((0%, 50%), (4%, 4%)), - ((50%, 0%), (4%, 4%)), - ), - path( - fill: purple, - stroke: 1pt, - (0pt, 0pt), - (30pt, 30pt), - (0pt, 30pt), - (30pt, 0pt), - ), - path( - fill: blue, - stroke: 1pt, - closed: true, - ((30%, 0%), (35%, 30%), (-20%, 0%)), - ((30%, 60%), (-20%, 0%), (0%, 0%)), - ((50%, 30%), (60%, -30%), (60%, 0%)), - ), - path( - stroke: 5pt, - closed: true, - (0pt, 30pt), - (30pt, 30pt), - (15pt, 0pt), - ), -) - ---- -// Error: 7-9 path vertex must have 1, 2, or 3 points -#path(()) - ---- -// Error: 7-47 path vertex must have 1, 2, or 3 points -#path(((0%, 0%), (0%, 0%), (0%, 0%), (0%, 0%))) - ---- -// Error: 7-31 point array must contain exactly two entries -#path(((0%, 0%), (0%, 0%, 0%))) diff --git a/tests/typ/visualize/pattern-relative.typ b/tests/typ/visualize/pattern-relative.typ deleted file mode 100644 index 78517e1e..00000000 --- a/tests/typ/visualize/pattern-relative.typ +++ /dev/null @@ -1,23 +0,0 @@ -// Test pattern with different `relative`. - ---- -// Test with relative set to `"self"` -#let pat(..args) = pattern(size: (30pt, 30pt), ..args)[ - #place(top + left, line(start: (0%, 0%), end: (100%, 100%), stroke: 1pt)) - #place(top + left, line(start: (0%, 100%), end: (100%, 0%), stroke: 1pt)) -] - -#set page(fill: pat(), width: 100pt, height: 100pt) - -#rect(fill: pat(relative: "self"), width: 100%, height: 100%, stroke: 1pt) - ---- -// Test with relative set to `"parent"` -#let pat(..args) = pattern(size: (30pt, 30pt), ..args)[ - #place(top + left, line(start: (0%, 0%), end: (100%, 100%), stroke: 1pt)) - #place(top + left, line(start: (0%, 100%), end: (100%, 0%), stroke: 1pt)) -] - -#set page(fill: pat(), width: 100pt, height: 100pt) - -#rect(fill: pat(relative: "parent"), width: 100%, height: 100%, stroke: 1pt) diff --git a/tests/typ/visualize/pattern-simple.typ b/tests/typ/visualize/pattern-simple.typ deleted file mode 100644 index 9c41067d..00000000 --- a/tests/typ/visualize/pattern-simple.typ +++ /dev/null @@ -1,18 +0,0 @@ -// Tests that simple patterns work. - ---- -#set page(width: auto, height: auto, margin: 0pt) -#let pat = pattern(size: (10pt, 10pt), line(stroke: 4pt, start: (0%, 0%), end: (100%, 100%))) -#rect(width: 50pt, height: 50pt, fill: pat) - ---- -#set page(width: auto, height: auto, margin: 0pt) - -#let pat = pattern(size: (10pt, 10pt), { - place(line(stroke: 4pt, start: (0%, 0%), end: (100%, 100%))) - place(line(stroke: 4pt, start: (100%,0%), end: (200%, 100%))) - place(line(stroke: 4pt, start: (0%,100%), end: (100%, 200%))) - place(line(stroke: 4pt, start: (-100%,0%), end: (0%, 100%))) - place(line(stroke: 4pt, start: (0%,-100%), end: (100%, 0%))) -}) -#rect(width: 50pt, height: 50pt, fill: pat) diff --git a/tests/typ/visualize/pattern-small.typ b/tests/typ/visualize/pattern-small.typ deleted file mode 100644 index 1d289f92..00000000 --- a/tests/typ/visualize/pattern-small.typ +++ /dev/null @@ -1,19 +0,0 @@ -// Tests small patterns for pixel accuracy. - ---- -#box( - width: 8pt, - height: 1pt, - fill: pattern(size: (1pt, 1pt), square(size: 1pt, fill: black)) -) -#v(-1em) -#box( - width: 8pt, - height: 1pt, - fill: pattern(size: (2pt, 1pt), square(size: 1pt, fill: black)) -) - ---- -// Error: 15-52 pattern tile size must be non-zero -// Hint: 15-52 try setting the size manually -#line(stroke: pattern(path((0pt, 0pt), (1em, 0pt)))) diff --git a/tests/typ/visualize/pattern-spacing.typ b/tests/typ/visualize/pattern-spacing.typ deleted file mode 100644 index f8f5f9fd..00000000 --- a/tests/typ/visualize/pattern-spacing.typ +++ /dev/null @@ -1,31 +0,0 @@ -// Test pattern with different `spacing`. - ---- -// Test with spacing set to `(-10pt, -10pt)` -#let pat(..args) = pattern(size: (30pt, 30pt), ..args)[ - #square(width: 100%, height: 100%, stroke: 1pt, fill: blue) -] - -#set page(width: 100pt, height: 100pt) - -#rect(fill: pat(spacing: (-10pt, -10pt)), width: 100%, height: 100%, stroke: 1pt) - ---- -// Test with spacing set to `(0pt, 0pt)` -#let pat(..args) = pattern(size: (30pt, 30pt), ..args)[ - #square(width: 100%, height: 100%, stroke: 1pt, fill: blue) -] - -#set page(width: 100pt, height: 100pt) - -#rect(fill: pat(spacing: (0pt, 0pt)), width: 100%, height: 100%, stroke: 1pt) - ---- -// Test with spacing set to `(10pt, 10pt)` -#let pat(..args) = pattern(size: (30pt, 30pt), ..args)[ - #square(width: 100%, height: 100%, stroke: 1pt, fill: blue) -] - -#set page(width: 100pt, height: 100pt) - -#rect(fill: pat(spacing: (10pt, 10pt,)), width: 100%, height: 100%, stroke: 1pt) diff --git a/tests/typ/visualize/pattern-stroke.typ b/tests/typ/visualize/pattern-stroke.typ deleted file mode 100644 index 3cc43a70..00000000 --- a/tests/typ/visualize/pattern-stroke.typ +++ /dev/null @@ -1,13 +0,0 @@ -// Test pattern on strokes - ---- -#align( - center + top, - square( - size: 50pt, - stroke: 5pt + pattern( - size: (5pt, 5pt), - align(horizon + center, circle(fill: blue, radius: 2.5pt)) - ) - ) -) diff --git a/tests/typ/visualize/pattern-text.typ b/tests/typ/visualize/pattern-text.typ deleted file mode 100644 index a9fbfb37..00000000 --- a/tests/typ/visualize/pattern-text.typ +++ /dev/null @@ -1,28 +0,0 @@ -// Test a pattern on some text - ---- -// You shouldn't be able to see the text, if you can then -// that means that the transform matrices are not being -// applied to the text correctly. -#let pat = pattern( - size: (30pt, 30pt), - relative: "parent", - square(size: 30pt, fill: gradient.conic(..color.map.rainbow)) -); - -#set page( - width: 140pt, - height: 140pt, - fill: pat -) - -#rotate(45deg, scale(x: 50%, y: 70%, rect( - width: 100%, - height: 100%, - stroke: 1pt, -)[ - #lorem(10) - - #set text(fill: pat) - #lorem(10) -])) diff --git a/tests/typ/visualize/polygon.typ b/tests/typ/visualize/polygon.typ deleted file mode 100644 index cad62497..00000000 --- a/tests/typ/visualize/polygon.typ +++ /dev/null @@ -1,36 +0,0 @@ -// Test polygons. - ---- -#set page(width: 50pt) -#set polygon(stroke: 0.75pt, fill: blue) - -// These are not visible, but should also not give an error -#polygon() -#polygon((0em, 0pt)) -#polygon((0pt, 0pt), (10pt, 0pt)) -#polygon.regular(size: 0pt, vertices: 9) - -#polygon((5pt, 0pt), (0pt, 10pt), (10pt, 10pt)) -#polygon( - (0pt, 0pt), (5pt, 5pt), (10pt, 0pt), - (15pt, 5pt), - (5pt, 10pt) -) -#polygon(stroke: none, (5pt, 0pt), (0pt, 10pt), (10pt, 10pt)) -#polygon(stroke: 3pt, fill: none, (5pt, 0pt), (0pt, 10pt), (10pt, 10pt)) - -// Relative size -#polygon((0pt, 0pt), (100%, 5pt), (50%, 10pt)) - -// Antiparallelogram -#polygon((0pt, 5pt), (5pt, 0pt), (0pt, 10pt), (5pt, 15pt)) - -// Self-intersections -#polygon((0pt, 10pt), (30pt, 20pt), (0pt, 30pt), (20pt, 0pt), (20pt, 35pt)) - -// Regular polygon; should have equal side lengths -#for k in range(3, 9) {polygon.regular(size: 30pt, vertices: k,)} - ---- -// Error: 10-17 point array must contain exactly two entries -#polygon((50pt,)) diff --git a/tests/typ/visualize/shape-aspect.typ b/tests/typ/visualize/shape-aspect.typ deleted file mode 100644 index d3606808..00000000 --- a/tests/typ/visualize/shape-aspect.typ +++ /dev/null @@ -1,63 +0,0 @@ -// Test that squares and circles respect their 1-1 aspect ratio. - ---- -// Test relative width and height and size that is smaller -// than default size. -#set page(width: 120pt, height: 70pt) -#set align(bottom) -#let centered = align.with(center + horizon) -#stack( - dir: ltr, - spacing: 1fr, - square(width: 50%, centered[A]), - square(height: 50%), - stack( - square(size: 10pt), - square(size: 20pt, centered[B]) - ), -) - ---- -// Test alignment in automatically sized square and circle. -#set text(8pt) -#box(square(inset: 4pt)[ - Hey there, #align(center + bottom, rotate(180deg, [you!])) -]) -#box(circle(align(center + horizon, [Hey.]))) - ---- -// Test that minimum wins if both width and height are given. -#stack( - dir: ltr, - spacing: 2pt, - square(width: 20pt, height: 40pt), - circle(width: 20%, height: 100pt), -) - ---- -// Test square that is limited by region size. -#set page(width: 20pt, height: 10pt, margin: 0pt) -#stack(dir: ltr, square(fill: forest), square(fill: conifer)) - ---- -// Test different ways of sizing. -#set page(width: 120pt, height: 40pt) -#stack( - dir: ltr, - spacing: 2pt, - circle(radius: 5pt), - circle(width: 10%), - circle(height: 50%), -) - ---- -// Test that square doesn't overflow due to its aspect ratio. -#set page(width: 40pt, height: 25pt, margin: 5pt) -#square(width: 100%) -#square(width: 100%)[Hello there] - ---- -// Size cannot be relative because we wouldn't know -// relative to which axis. -// Error: 15-18 expected length or auto, found ratio -#square(size: 50%) diff --git a/tests/typ/visualize/shape-circle.typ b/tests/typ/visualize/shape-circle.typ deleted file mode 100644 index 34238d9a..00000000 --- a/tests/typ/visualize/shape-circle.typ +++ /dev/null @@ -1,58 +0,0 @@ -// Test the `circle` function. - ---- -// Default circle. -#box(circle()) -#box(circle[Hey]) - ---- -// Test auto sizing. -#set circle(inset: 0pt) - -Auto-sized circle. -#circle(fill: rgb("eb5278"), stroke: 2pt + black, - align(center + horizon)[But, soft!] -) - -Center-aligned rect in auto-sized circle. -#circle(fill: forest, stroke: conifer, - align(center + horizon, - rect(fill: conifer, inset: 5pt)[But, soft!] - ) -) - -Rect in auto-sized circle. -#circle(fill: forest, - rect(fill: conifer, stroke: white, inset: 4pt)[ - #set text(8pt) - But, soft! what light through yonder window breaks? - ] -) - -Expanded by height. -#circle(stroke: black, align(center)[A \ B \ C]) - ---- -// Ensure circle directly in rect works. -#rect(width: 40pt, height: 30pt, fill: forest, - circle(fill: conifer)) - ---- -// Test relative sizing. -#set text(fill: white) -#show: rect.with(width: 100pt, height: 50pt, inset: 0pt, fill: rgb("aaa")) -#set align(center + horizon) -#stack( - dir: ltr, - spacing: 1fr, - 1fr, - circle(radius: 10pt, fill: eastern, [A]), // D=20pt - circle(height: 60%, fill: eastern, [B]), // D=30pt - circle(width: 20% + 20pt, fill: eastern, [C]), // D=40pt - 1fr, -) - ---- -// Radius wins over width and height. -// Error: 23-34 unexpected argument: width -#circle(radius: 10pt, width: 50pt, height: 100pt, fill: eastern) diff --git a/tests/typ/visualize/shape-ellipse.typ b/tests/typ/visualize/shape-ellipse.typ deleted file mode 100644 index 2fd4acd9..00000000 --- a/tests/typ/visualize/shape-ellipse.typ +++ /dev/null @@ -1,31 +0,0 @@ -// Test the `ellipse` function. - ---- -// Default ellipse. -#ellipse() - ---- -#set rect(inset: 0pt) -#set ellipse(inset: 0pt) - -Rect in ellipse in fixed rect. -#rect(width: 3cm, height: 2cm, fill: rgb("2a631a"), - ellipse(fill: forest, width: 100%, height: 100%, - rect(fill: conifer, width: 100%, height: 100%, - align(center + horizon)[ - Stuff inside an ellipse! - ] - ) - ) -) - -Auto-sized ellipse. -#ellipse(fill: conifer, stroke: 3pt + forest, inset: 3pt)[ - #set text(8pt) - But, soft! what light through yonder window breaks? -] - - -An inline -#box(ellipse(width: 8pt, height: 6pt, outset: (top: 3pt, rest: 5.5pt))) -ellipse. diff --git a/tests/typ/visualize/shape-fill-stroke.typ b/tests/typ/visualize/shape-fill-stroke.typ deleted file mode 100644 index 8d187400..00000000 --- a/tests/typ/visualize/shape-fill-stroke.typ +++ /dev/null @@ -1,93 +0,0 @@ -// Test shape fill & stroke. - ---- -#let variant = rect.with(width: 20pt, height: 10pt) -#let items = for (i, item) in ( - variant(stroke: none), - variant(), - variant(fill: none), - variant(stroke: 2pt), - variant(stroke: eastern), - variant(stroke: eastern + 2pt), - variant(fill: eastern), - variant(fill: eastern, stroke: none), - variant(fill: forest, stroke: none), - variant(fill: forest, stroke: conifer), - variant(fill: forest, stroke: black + 2pt), - variant(fill: forest, stroke: conifer + 2pt), -).enumerate() { - (align(horizon)[#(i + 1).], item, []) -} - -#grid( - columns: (auto, auto, 1fr, auto, auto, 0fr), - gutter: 5pt, - ..items, -) - ---- -// Test stroke folding. -#let sq(..args) = box(square(size: 10pt, ..args)) - -#set square(stroke: none) -#sq() -#set square(stroke: auto) -#sq() -#sq(fill: teal) -#sq(stroke: 2pt) -#sq(stroke: blue) -#sq(fill: teal, stroke: blue) -#sq(fill: teal, stroke: 2pt + blue) - ---- -// Test stroke composition. -#set square(stroke: 4pt) -#set text(font: "Roboto") -#stack( - dir: ltr, - square( - stroke: (left: red, top: yellow, right: green, bottom: blue), - radius: 50%, align(center+horizon)[*G*], - inset: 8pt - ), - h(0.5cm), - square( - stroke: (left: red, top: yellow + 8pt, right: green, bottom: blue + 2pt), - radius: 50%, align(center+horizon)[*G*], - inset: 8pt - ), - h(0.5cm), - square( - stroke: (left: red, top: yellow, right: green, bottom: blue), - radius: 100%, align(center+horizon)[*G*], - inset: 8pt - ), -) - -// Join between different solid strokes -#set square(size: 20pt, stroke: 2pt) -#set square(stroke: (left: green + 4pt, top: black + 2pt, right: blue, bottom: black + 2pt)) -#stack( - dir: ltr, - square(), - h(0.2cm), - square(radius: (top-left: 0pt, rest: 1pt)), - h(0.2cm), - square(radius: (top-left: 0pt, rest: 8pt)), - h(0.2cm), - square(radius: (top-left: 0pt, rest: 100pt)), -) - - -// Join between solid and dotted strokes -#set square(stroke: (left: green + 4pt, top: black + 2pt, right: (paint: blue, dash: "dotted"), bottom: (paint: black, dash: "dotted"))) -#stack( - dir: ltr, - square(), - h(0.2cm), - square(radius: (top-left: 0pt, rest: 1pt)), - h(0.2cm), - square(radius: (top-left: 0pt, rest: 8pt)), - h(0.2cm), - square(radius: (top-left: 0pt, rest: 100pt)), -) diff --git a/tests/typ/visualize/shape-rect.typ b/tests/typ/visualize/shape-rect.typ deleted file mode 100644 index bd9cf1ae..00000000 --- a/tests/typ/visualize/shape-rect.typ +++ /dev/null @@ -1,78 +0,0 @@ -// Test the `rect` function. - ---- -// Default rectangle. -#rect() - ---- -#set page(width: 150pt) - -// Fit to text. -#rect(fill: conifer)[Textbox] - -// Empty with fixed width and height. -#block(rect( - height: 15pt, - fill: rgb("46b3c2"), - stroke: 2pt + rgb("234994"), -)) - -// Fixed width, text height. -#rect(width: 2cm, fill: rgb("9650d6"))[Fixed and padded] - -// Page width, fixed height. -#rect(height: 1cm, width: 100%, fill: rgb("734ced"))[Topleft] - -// These are inline with text. -{#box(rect(width: 0.5in, height: 7pt, fill: rgb("d6cd67"))) - #box(rect(width: 0.5in, height: 7pt, fill: rgb("edd466"))) - #box(rect(width: 0.5in, height: 7pt, fill: rgb("e3be62")))} - -// Rounded corners. -#stack( - dir: ltr, - spacing: 1fr, - rect(width: 2cm, radius: 30%), - rect(width: 1cm, radius: (left: 10pt, right: 5pt)), - rect(width: 1.25cm, radius: ( - top-left: 2pt, - top-right: 5pt, - bottom-right: 8pt, - bottom-left: 11pt - )), -) - -// Different strokes. -#set rect(stroke: (right: red)) -#rect(width: 100%, fill: lime, stroke: (x: 5pt, y: 1pt)) - ---- -// Error: 15-38 unexpected key "cake", valid keys are "top-left", "top-right", "bottom-right", "bottom-left", "left", "top", "right", "bottom", and "rest" -#rect(radius: (left: 10pt, cake: 5pt)) - ---- -// Error: 15-21 expected length, color, gradient, pattern, dictionary, stroke, none, or auto, found array -#rect(stroke: (1, 2)) - ---- -#set page(width: 17.8cm) -#lorem(100) -#rect(lorem(100)) -#set par(justify: true) -#lorem(100) -#rect(lorem(100)) - ---- -// Negative dimensions -#rect(width: -1cm, fill: gradient.linear(red, blue))[Reverse left] - -#rect(width: 1cm, fill: gradient.linear(red, blue))[Left] - -#align(center, rect(width: -1cm, fill: gradient.linear(red, blue))[Reverse center]) - -#align(center, rect(width: 1cm, fill: gradient.linear(red, blue))[Center]) - -#align(right, rect(width: -1cm, fill: gradient.linear(red, blue))[Reverse right]) - -#align(right, rect(width: 1cm, fill: gradient.linear(red, blue))[Right]) - diff --git a/tests/typ/visualize/shape-rounded.typ b/tests/typ/visualize/shape-rounded.typ deleted file mode 100644 index 42432dc9..00000000 --- a/tests/typ/visualize/shape-rounded.typ +++ /dev/null @@ -1,53 +0,0 @@ -// Test rounded rectangles and squares. - ---- -#set square(size: 20pt, stroke: 4pt) - -// no radius for non-rounded corners -#stack( - dir: ltr, - square(), - h(10pt), - square(radius: 0pt), - h(10pt), - square(radius: -10pt), -) - -#stack( - dir: ltr, - square(), - h(10pt), - square(radius: 0%), - h(10pt), - square(radius: -10%), -) - - -// small values for small radius -#stack( - dir: ltr, - square(radius: 1pt), - h(10pt), - square(radius: 5%), - h(10pt), - square(radius: 2pt), -) - -// large values for large radius or circle -#stack( - dir: ltr, - square(radius: 8pt), - h(10pt), - square(radius: 10pt), - h(10pt), - square(radius: 12pt), -) - -#stack( - dir: ltr, - square(radius: 45%), - h(10pt), - square(radius: 50%), - h(10pt), - square(radius: 55%), -) diff --git a/tests/typ/visualize/shape-square.typ b/tests/typ/visualize/shape-square.typ deleted file mode 100644 index a321dc4a..00000000 --- a/tests/typ/visualize/shape-square.typ +++ /dev/null @@ -1,39 +0,0 @@ -// Test the `square` function. - ---- -// Default square. -#box(square()) -#box(square[hey!]) - ---- -// Test auto-sized square. -#square(fill: eastern)[ - #set text(fill: white, weight: "bold") - Typst -] - ---- -// Test relative-sized child. -#square(fill: eastern)[ - #rect(width: 10pt, height: 5pt, fill: conifer) - #rect(width: 40%, height: 5pt, stroke: conifer) -] - ---- -// Test text overflowing height. -#set page(width: 75pt, height: 100pt) -#square(fill: conifer)[ - But, soft! what light through yonder window breaks? -] - ---- -// Test that square does not overflow page. -#set page(width: 100pt, height: 75pt) -#square(fill: conifer)[ - But, soft! what light through yonder window breaks? -] - ---- -// Size wins over width and height. -// Error: 09-20 unexpected argument: width -#square(width: 10cm, height: 20cm, size: 1cm, fill: rgb("eb5278")) diff --git a/tests/typ/visualize/stroke.typ b/tests/typ/visualize/stroke.typ deleted file mode 100644 index cf91dcc3..00000000 --- a/tests/typ/visualize/stroke.typ +++ /dev/null @@ -1,115 +0,0 @@ -// Test lines. - ---- -// Some simple test lines -#line(length: 60pt, stroke: red) -#v(3pt) -#line(length: 60pt, stroke: 2pt) -#v(3pt) -#line(length: 60pt, stroke: blue + 1.5pt) -#v(3pt) -#line(length: 60pt, stroke: (paint: red, thickness: 1pt, dash: "dashed")) -#v(3pt) -#line(length: 60pt, stroke: (paint: red, thickness: 4pt, cap: "round")) - ---- -// Set rules with stroke -#set line(stroke: (paint: red, thickness: 1pt, cap: "butt", dash: "dash-dotted")) -#line(length: 60pt) -#v(3pt) -#line(length: 60pt, stroke: blue) -#v(3pt) -#line(length: 60pt, stroke: (dash: none)) - ---- -// Rectangle strokes -#rect(width: 20pt, height: 20pt, stroke: red) -#v(3pt) -#rect(width: 20pt, height: 20pt, stroke: (rest: red, top: (paint: blue, dash: "dashed"))) -#v(3pt) -#rect(width: 20pt, height: 20pt, stroke: (thickness: 5pt, join: "round")) - ---- -// Dashing -#line(length: 60pt, stroke: (paint: red, thickness: 1pt, dash: ("dot", 1pt))) -#v(3pt) -#line(length: 60pt, stroke: (paint: red, thickness: 1pt, dash: ("dot", 1pt, 4pt, 2pt))) -#v(3pt) -#line(length: 60pt, stroke: (paint: red, thickness: 1pt, dash: (array: ("dot", 1pt, 4pt, 2pt), phase: 5pt))) -#v(3pt) -#line(length: 60pt, stroke: (paint: red, thickness: 1pt, dash: ())) -#v(3pt) -#line(length: 60pt, stroke: (paint: red, thickness: 1pt, dash: (1pt, 3pt, 9pt))) - ---- -// Line joins -#stack( - dir: ltr, - spacing: 1em, - polygon(stroke: (thickness: 4pt, paint: blue, join: "round"), - (0pt, 20pt), (15pt, 0pt), (0pt, 40pt), (15pt, 45pt)), - polygon(stroke: (thickness: 4pt, paint: blue, join: "bevel"), - (0pt, 20pt), (15pt, 0pt), (0pt, 40pt), (15pt, 45pt)), - polygon(stroke: (thickness: 4pt, paint: blue, join: "miter"), - (0pt, 20pt), (15pt, 0pt), (0pt, 40pt), (15pt, 45pt)), - polygon(stroke: (thickness: 4pt, paint: blue, join: "miter", miter-limit: 20.0), - (0pt, 20pt), (15pt, 0pt), (0pt, 40pt), (15pt, 45pt)), -) ---- -// Error: 29-56 unexpected key "thicknes", valid keys are "paint", "thickness", "cap", "join", "dash", and "miter-limit" -#line(length: 60pt, stroke: (paint: red, thicknes: 1pt)) - ---- -// Error: 29-55 expected "solid", "dotted", "densely-dotted", "loosely-dotted", "dashed", "densely-dashed", "loosely-dashed", "dash-dotted", "densely-dash-dotted", "loosely-dash-dotted", array, dictionary, none, or auto -#line(length: 60pt, stroke: (paint: red, dash: "dash")) - ---- -// 0pt strokes must function exactly like 'none' strokes and not draw anything -#rect(width: 10pt, height: 10pt, stroke: none) -#rect(width: 10pt, height: 10pt, stroke: 0pt) -#rect(width: 10pt, height: 10pt, stroke: none, fill: blue) -#rect(width: 10pt, height: 10pt, stroke: 0pt + red, fill: blue) - -#line(length: 30pt, stroke: 0pt) -#line(length: 30pt, stroke: (paint: red, thickness: 0pt, dash: ("dot", 1pt))) - -#table(columns: 2, stroke: none)[A][B] -#table(columns: 2, stroke: 0pt)[A][B] - -#path( - fill: red, - stroke: none, - closed: true, - ((0%, 0%), (4%, -4%)), - ((50%, 50%), (4%, -4%)), - ((0%, 50%), (4%, 4%)), - ((50%, 0%), (4%, 4%)), -) - -#path( - fill: red, - stroke: 0pt, - closed: true, - ((0%, 0%), (4%, -4%)), - ((50%, 50%), (4%, -4%)), - ((0%, 50%), (4%, 4%)), - ((50%, 0%), (4%, 4%)), -) - ---- -// Converting to stroke -#assert.eq(stroke(red).paint, red) -#assert.eq(stroke(red).thickness, auto) -#assert.eq(stroke(2pt).paint, auto) -#assert.eq(stroke((cap: "round", paint: blue)).cap, "round") -#assert.eq(stroke((cap: auto, paint: blue)).cap, auto) -#assert.eq(stroke((cap: auto, paint: blue)).thickness, auto) - -// Error: 9-21 unexpected key "foo", valid keys are "paint", "thickness", "cap", "join", "dash", and "miter-limit" -#stroke((foo: "bar")) - -// Constructing with named arguments -#assert.eq(stroke(paint: blue, thickness: 8pt), 8pt + blue) -#assert.eq(stroke(thickness: 2pt), stroke(2pt)) -#assert.eq(stroke(cap: "round").thickness, auto) -#assert.eq(stroke(cap: "round", thickness: auto).thickness, auto) diff --git a/tests/typ/visualize/svg-text.typ b/tests/typ/visualize/svg-text.typ deleted file mode 100644 index 6f0a758e..00000000 --- a/tests/typ/visualize/svg-text.typ +++ /dev/null @@ -1,18 +0,0 @@ -// Test SVG with text. - ---- -#set page(width: 250pt) - -#figure( - image("/assets/images/diagram.svg"), - caption: [A textful diagram], -) - ---- -#set page(width: 250pt) -#show image: set text(font: ("Roboto", "Noto Serif CJK SC")) - -#figure( - image("/assets/images/chinese.svg"), - caption: [Bilingual text] -) |
