99 lines
4.2 KiB
Python
99 lines
4.2 KiB
Python
|
|
import pytest
|
|||
|
|
from lxml import etree
|
|||
|
|
|
|||
|
|
from conftest import PNG, SVG, Book, Doc
|
|||
|
|
from epub2md.mathml import Unsupported, mathml_to_tex
|
|||
|
|
|
|||
|
|
M = 'xmlns="http://www.w3.org/1998/Math/MathML"'
|
|||
|
|
|
|||
|
|
|
|||
|
|
def tex(xml: str) -> str:
|
|||
|
|
return mathml_to_tex(etree.fromstring(f"<math {M}>{xml}</math>"))
|
|||
|
|
|
|||
|
|
|
|||
|
|
@pytest.mark.parametrize(
|
|||
|
|
("xml", "expected"),
|
|||
|
|
[
|
|||
|
|
("<mfrac><mi>a</mi><mi>b</mi></mfrac>", r"\frac{a}{b}"),
|
|||
|
|
("<msup><mi>x</mi><mn>2</mn></msup>", "x^{2}"),
|
|||
|
|
("<msub><mi>a</mi><mi>i</mi></msub>", "a_{i}"),
|
|||
|
|
("<msubsup><mi>x</mi><mi>i</mi><mn>2</mn></msubsup>", "x_{i}^{2}"),
|
|||
|
|
("<msqrt><mi>x</mi></msqrt>", r"\sqrt{x}"),
|
|||
|
|
("<mroot><mi>x</mi><mn>3</mn></mroot>", r"\sqrt[3]{x}"),
|
|||
|
|
("<munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><msub><mi>a</mi><mi>i</mi></msub>",
|
|||
|
|
r"\sum_{i = 1}^{n} a_{i}"),
|
|||
|
|
("<mi>α</mi><mo>≤</mo><mi>β</mi>", r"\alpha \leq \beta"),
|
|||
|
|
("<mover><mi>x</mi><mo>^</mo></mover>", r"\hat{x}"),
|
|||
|
|
("<mi mathvariant='double-struck'>R</mi>", r"\mathbb{R}"),
|
|||
|
|
("<mtext>für alle</mtext>", r"\text{für alle}"),
|
|||
|
|
("<mrow><mo>(</mo><mtable><mtr><mtd><mn>1</mn></mtd><mtd><mn>0</mn></mtd></mtr>"
|
|||
|
|
"<mtr><mtd><mn>0</mn></mtd><mtd><mn>1</mn></mtd></mtr></mtable><mo>)</mo></mrow>",
|
|||
|
|
r"\left( \begin{matrix} 1 & 0 \\ 0 & 1 \end{matrix} \right)"),
|
|||
|
|
],
|
|||
|
|
)
|
|||
|
|
def test_mathml_to_tex(xml, expected):
|
|||
|
|
assert tex(xml) == expected
|
|||
|
|
|
|||
|
|
|
|||
|
|
def test_tex_annotation_is_preferred():
|
|||
|
|
xml = ('<semantics><mi>x</mi><annotation encoding="application/x-tex">\\mathbf{x}</annotation></semantics>')
|
|||
|
|
assert tex(xml) == r"\mathbf{x}"
|
|||
|
|
|
|||
|
|
|
|||
|
|
@pytest.mark.parametrize("xml", ["<menclose><mi>x</mi></menclose>", "<mmultiscripts><mi>x</mi></mmultiscripts>",
|
|||
|
|
"<mtable><mlabeledtr><mtd>1</mtd></mlabeledtr></mtable>"])
|
|||
|
|
def test_unsupported_mathml_raises(xml):
|
|||
|
|
with pytest.raises(Unsupported):
|
|||
|
|
tex(xml)
|
|||
|
|
|
|||
|
|
|
|||
|
|
BODY = (
|
|||
|
|
"<h1>Formeln</h1>"
|
|||
|
|
f'<p>Inline <math {M}><mfrac><mi>a</mi><mi>b</mi></mfrac></math> im Satz.</p>'
|
|||
|
|
f'<div class="equation"><math {M} display="block"><msup><mi>x</mi><mn>2</mn></msup></math> <span>(3.7)</span></div>'
|
|||
|
|
f'<p>Unbekannt: <math {M}><menclose notation="box"><mi>z</mi></menclose></math></p>'
|
|||
|
|
'<p>SVG: <span class="math"><img src="f.svg" alt="Formel 1"/></span></p>'
|
|||
|
|
'<p>Bild ohne TeX: <span class="equation"><img src="eq.png" alt="Summe"/></span></p>'
|
|||
|
|
'<p>Bild mit TeX: <span class="InlineEquation"><img src="eq2.png" alt="$$a &amp; b \\leq c$$"/></span></p>'
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def math_book() -> Book:
|
|||
|
|
return Book(docs=[Doc("m.xhtml", BODY)], media={"f.svg": SVG, "eq.png": PNG, "eq2.png": PNG})
|
|||
|
|
|
|||
|
|
|
|||
|
|
def test_math_auto(convert):
|
|||
|
|
run = convert(math_book())
|
|||
|
|
text = run.chapter("001")
|
|||
|
|
assert r"Inline $\frac{a}{b}$ im Satz." in text
|
|||
|
|
assert "$$\nx^{2}\n$$" in text
|
|||
|
|
assert "(3.7)" in text # equation number visible
|
|||
|
|
assert "<math" in text and "menclose" in text # unsupported MathML kept, not lost
|
|||
|
|
assert "]
|
|||
|
|
assert svgs and svgs[0]["media_type"] == "image/svg+xml"
|
|||
|
|
|
|||
|
|
|
|||
|
|
def test_math_tex_mode_uses_backslash_delimiters(convert):
|
|||
|
|
text = convert(math_book(), "--math", "tex").chapter("001")
|
|||
|
|
assert r"\(\frac{a}{b}\)" in text
|
|||
|
|
assert "\\[\nx^{2}\n\\]" in text
|
|||
|
|
assert "$" not in text.replace("\\$", "")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def test_math_mathml_mode_keeps_mathml(convert):
|
|||
|
|
text = convert(math_book(), "--math", "mathml").chapter("001")
|
|||
|
|
assert '<math xmlns="http://www.w3.org/1998/Math/MathML"><mfrac><mi>a</mi><mi>b</mi></mfrac></math>' in text
|
|||
|
|
assert "frac{" not in text
|
|||
|
|
|
|||
|
|
|
|||
|
|
def test_math_image_mode(convert):
|
|||
|
|
run = convert(math_book(), "--math", "image")
|
|||
|
|
text = run.chapter("001")
|
|||
|
|
assert text.count("![") == 3 # svg + both formula images
|
|||
|
|
assert "<math" in text # pure MathML without image is not lost
|
|||
|
|
assert any(w["code"] == "mathml-no-image" for w in run.report["warnings"])
|