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/introspection | |
| parent | 72dd79210602ecc799726fc096b078afbb47f299 (diff) | |
Better test runner (#3922)
Diffstat (limited to 'tests/suite/introspection')
| -rw-r--r-- | tests/suite/introspection/counter.typ | 78 | ||||
| -rw-r--r-- | tests/suite/introspection/here.typ | 3 | ||||
| -rw-r--r-- | tests/suite/introspection/locate.typ | 32 | ||||
| -rw-r--r-- | tests/suite/introspection/query.typ | 267 | ||||
| -rw-r--r-- | tests/suite/introspection/state.typ | 63 |
5 files changed, 443 insertions, 0 deletions
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>) |
