ipynb2html/test/mathExtractor.test.ts

147 lines
4.2 KiB
TypeScript

import dedent from 'dedent'
import { extractMath, restoreMath } from '@/mathExtractor'
describe('.extractMath', () => {
describe.each([
/* delimiters | displayMode */
['$...$' , false],
['$$...$$' , true ],
['\\\\(...\\\\)', false],
['\\\\[...\\\\]', true ],
] as Array<[string, boolean]>)(
'text with expression delimited using %s', (delimiters, displayMode) => {
describe('on a single line', () => {
const value = 'x = 42'
const raw = delimiters.replace('...', value)
it('extracts and substitutes math expression in the given text', () => {
expect(
extractMath(`Let's define ${raw}.`)
).toEqual([`Let's define @@1@@.`, [{ displayMode, raw, value }]])
})
})
describe('on multiple lines', () => {
const value = 'x = 42\ny = 55'
const raw = delimiters.replace('...', `\n ${value}\n`)
it('extracts and substitutes math expression in the given text', () => {
expect(
extractMath(`Let's define ${raw}.`)
).toEqual([`Let's define @@1@@.`, [{ displayMode, raw, value }]])
})
})
}
)
describe('text with \\begin{..} ... \\end{..} expression', () => {
const raw = '\\begin{equation}a_{0}+ b_{T}\\end{equation}'
it('extracts and substitutes math expression in the given text', () => {
expect(
extractMath(`Let's define ${raw}.`)
).toEqual([`Let's define @@1@@.`, [{ displayMode: true, raw, value: raw }]])
})
})
describe('text with marker-like sequences', () => {
it('escapes @@[0-9]+@@ as @@0[0-9]+@@', () => {
expect(
extractMath('This @@02@@ is not our marker')
).toEqual(['This @@002@@ is not our marker', []])
})
})
it('ignores math delimiters inside `inline code`', () => {
expect(
extractMath('`$x$` and ``$`x`$`` is a code, $x$ is not')
).toEqual([
'`$x$` and ``$`x`$`` is a code, @@1@@ is not',
[{ displayMode: false, raw: '$x$', value: 'x' }],
])
})
it('ignores math delimiters inside `inline code` with line breaks', () => {
expect(
extractMath('`$x\n$` and ``\n$`x`$\n`` is a code, `$x$\n\nis` not')
).toEqual([
'`$x\n$` and ``\n$`x`$\n`` is a code, `@@1@@\n\nis` not',
[{ displayMode: false, raw: '$x$', value: 'x' }],
])
})
it('ignores math delimiters inside ```fenced code blocks```', () => {
const text = dedent`
Some code:
\`\`\`sh
echo $foo $bar
\`\`\`
and $$ x = 42 $$
`
expect( extractMath(text) ).toEqual([
text.replace('$$ x = 42 $$', '@@1@@'),
[{ displayMode: true, raw: '$$ x = 42 $$', value: 'x = 42' }],
])
})
test('complex example', () => {
const eq2 = dedent`
\begin{aligned}
A_k &= \langle k, +\infty), &
B_k &= \{ p \mid p \ \text{is prvočíslo a} \ p < k \}
\end{aligned}
`
const text = dedent`
Define sets for natural $k$
\begin{aligned}
A_k &= \langle k, +\infty), &
B_k &= \{ p \mid p \ \text{is prvočíslo a} \ p < k \}
\end{aligned}
This @@1@@ is not a marker, this \`$x && $y\`
is not a math, but \\(x\\) and $$
x = 42
$$ is.
`
const expected = dedent`
Define sets for natural @@1@@
@@2@@
This @@01@@ is not a marker, this \`$x && $y\`
is not a math, but @@3@@ and @@4@@ is.
`
expect( extractMath(text) ).toEqual([expected, [
{ displayMode: false, raw: '$k$', value: 'k' },
{ displayMode: true, raw: eq2, value: eq2 },
{ displayMode: false, raw: '\\\\(x\\\\)', value: 'x' },
{ displayMode: true, raw: '$$\n x = 42\n$$', value: 'x = 42' },
]])
})
})
describe('.restoreMath', () => {
it('replaces markers with the given strings', () => {
const repl = ['first']
repl[21] = 'second'
expect(
restoreMath("Let's define @@1@@ and @@22@@.", repl)
).toEqual("Let's define first and second.")
})
it('unescapes marker-like sequences', () => {
expect(
restoreMath('This @@001@@ is not our marker, nor @@01@@, but @@1@@ is.', ['this one'])
).toEqual('This @@01@@ is not our marker, nor @@1@@, but this one is.')
})
})