diff options
| author | Laurenz <laurmaedje@gmail.com> | 2024-04-13 10:39:45 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-13 08:39:45 +0000 |
| commit | 020294fca9a7065d4b9cf4e677f606ebaaa29b00 (patch) | |
| tree | c0027ad22046e2726c22298461327823d6b88d53 /tests/suite/model | |
| parent | 72dd79210602ecc799726fc096b078afbb47f299 (diff) | |
Better test runner (#3922)
Diffstat (limited to 'tests/suite/model')
| -rw-r--r-- | tests/suite/model/bibliography.typ | 55 | ||||
| -rw-r--r-- | tests/suite/model/cite.typ | 92 | ||||
| -rw-r--r-- | tests/suite/model/document.typ | 36 | ||||
| -rw-r--r-- | tests/suite/model/emph-strong.typ | 74 | ||||
| -rw-r--r-- | tests/suite/model/enum.typ | 156 | ||||
| -rw-r--r-- | tests/suite/model/figure.typ | 220 | ||||
| -rw-r--r-- | tests/suite/model/footnote.typ | 182 | ||||
| -rw-r--r-- | tests/suite/model/heading.typ | 80 | ||||
| -rw-r--r-- | tests/suite/model/link.typ | 77 | ||||
| -rw-r--r-- | tests/suite/model/list.typ | 147 | ||||
| -rw-r--r-- | tests/suite/model/numbering.typ | 103 | ||||
| -rw-r--r-- | tests/suite/model/outline.typ | 176 | ||||
| -rw-r--r-- | tests/suite/model/par.typ | 78 | ||||
| -rw-r--r-- | tests/suite/model/quote.typ | 86 | ||||
| -rw-r--r-- | tests/suite/model/ref.typ | 56 | ||||
| -rw-r--r-- | tests/suite/model/terms.typ | 77 |
16 files changed, 1695 insertions, 0 deletions
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!] |
