diff --git a/doxygen/test/compound_template_specialization_inner_class/Doxyfile b/doxygen/test/compound_template_specialization_inner_class/Doxyfile new file mode 100644 index 00000000..49e476ec --- /dev/null +++ b/doxygen/test/compound_template_specialization_inner_class/Doxyfile @@ -0,0 +1,13 @@ +INPUT = File.h +QUIET = YES +GENERATE_HTML = NO +GENERATE_LATEX = NO +GENERATE_XML = YES +XML_PROGRAMLISTING = NO + +##! M_PAGE_FINE_PRINT = +##! M_THEME_COLOR = +##! M_FAVICON = +##! M_LINKS_NAVBAR1 = +##! M_LINKS_NAVBAR2 = +##! M_SEARCH_DISABLED = YES diff --git a/doxygen/test/compound_template_specialization_inner_class/File.h b/doxygen/test/compound_template_specialization_inner_class/File.h new file mode 100644 index 00000000..bcdcbe31 --- /dev/null +++ b/doxygen/test/compound_template_specialization_inner_class/File.h @@ -0,0 +1,19 @@ +/** @brief A templated structure */ +template struct S {}; + +/** @brief A templated structure specialization */ +template struct S { + /** @brief Inner struct */ + struct SS {}; +}; + +// template +// struct S +// { +// }; +// +// template +// struct S +// { +// struct SS {}; +// }; diff --git a/doxygen/test/compound_template_specialization_inner_class/File_8h.html b/doxygen/test/compound_template_specialization_inner_class/File_8h.html new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/doxygen/test/compound_template_specialization_inner_class/File_8h.html @@ -0,0 +1 @@ + diff --git a/doxygen/test/contents_custom/math-pre222.html b/doxygen/test/contents_custom/math-pre222.html new file mode 100644 index 00000000..49b9c541 --- /dev/null +++ b/doxygen/test/contents_custom/math-pre222.html @@ -0,0 +1,53 @@ + + + + + Math | My Project + + + + + +
+
+
+
+
+

+ Math +

+

A green formula:

+ +\[ \pi^2 \] + + + + + + + + + +

A yellow + +$ \Sigma $ + + + + + + + + inline formula.

+
+
+
+
+ + diff --git a/doxygen/test/contents_math/index-pre222.html b/doxygen/test/contents_math/index-pre222.html new file mode 100644 index 00000000..f7cc6df0 --- /dev/null +++ b/doxygen/test/contents_math/index-pre222.html @@ -0,0 +1,162 @@ + + + + + My Project + + + + + +
+
+
+
+
+

+ My Project +

+

Here's a block formula:

+ +\[ \hat q = [\boldsymbol 0, 1] + \epsilon [\frac{\boldsymbol v}{2}, 0] \] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

And + +$ \hat q $ + + + + + + + + + + is how quaternion is denoted.

+ +\[ a^2 + b^2 = c^2 \] + + + + + + + + + + + + + + + + + + + +

+ +$c^2$ + + + + + + + + + + should be part of a new paragraph, not stuck out of it. The following formula has a custom environment:

+ +\begin{eqnarray*} g &=& \frac{Gm_2}{r^2} \\ &=& 9.82066032\,\mbox{m/s}^2 \end{eqnarray*} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + diff --git a/doxygen/test/contents_math_cached/math-pre222.html b/doxygen/test/contents_math_cached/math-pre222.html new file mode 100644 index 00000000..d1a28679 --- /dev/null +++ b/doxygen/test/contents_math_cached/math-pre222.html @@ -0,0 +1,68 @@ + + + + + Math | My Project + + + + + +
+
+
+
+
+

+ Math +

+

In order to actually test use of the cache, I need to cheat a bit. Inline formula which is pi in the source but + +$ \pi $ + + + + + + + + + + + here. Then a block formula which is a Pythagorean theorem in source but not in the output:

+ +\[ a^2 + b^2 = c^2 \] + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + diff --git a/doxygen/test/test_contents.py b/doxygen/test/test_contents.py index 095e9a80..0c21ff03 100644 --- a/doxygen/test/test_contents.py +++ b/doxygen/test/test_contents.py @@ -38,6 +38,11 @@ def dot_version(): return re.match(".*version (?P\d+\.\d+\.\d+).*", subprocess.check_output(['dot', '-V'], stderr=subprocess.STDOUT).decode('utf-8').strip()).group('version') +def dvisvgm_version(): + # It's sometimes just "dvisvgm 2.3.5", other times + # "dvisvgm (TeX Live) 1.9.2", so use rpartition() + return subprocess.check_output(['dvisvgm', '--version'], stderr=subprocess.STDOUT).decode('utf-8').strip().rpartition(' ')[2] + class Typography(IntegrationTestCase): def __init__(self, *args, **kwargs): super().__init__(__file__, 'typography', *args, **kwargs) @@ -109,12 +114,18 @@ class Math(IntegrationTestCase): def __init__(self, *args, **kwargs): super().__init__(__file__, 'math', *args, **kwargs) - @unittest.skipUnless(shutil.which('latex'), - "Math rendering requires LaTeX installed") + @unittest.skipUnless(shutil.which('latex') and LooseVersion(dvisvgm_version()) >= LooseVersion("2.2.2"), + "Math rendering requires LaTeX installed, dvisvgm < 2.2.2 has vastly different output") def test(self): self.run_dox2html5(wildcard='indexpage.xml') self.assertEqual(*self.actual_expected_contents('index.html')) + @unittest.skipUnless(shutil.which('latex') and LooseVersion(dvisvgm_version()) < LooseVersion("2.2.2"), + "Math rendering requires LaTeX installed, dvisvgm < 2.2.2 has vastly different output") + def test_pre222(self): + self.run_dox2html5(wildcard='indexpage.xml') + self.assertEqual(*self.actual_expected_contents('index.html', 'index-pre222.html')) + @unittest.skipUnless(shutil.which('latex'), "Math rendering requires LaTeX installed") def test_latex_error(self): @@ -125,7 +136,7 @@ class MathCached(IntegrationTestCase): def __init__(self, *args, **kwargs): super().__init__(__file__, 'math_cached', *args, **kwargs) - # Actually generated from $ \frac{\tau}{2} $ tho + # Actually generated from $ \frac{\tau}{2} $ tho self.tau_half_hash = sha1("""$ \pi $""".encode('utf-8')).digest() self.tau_half = """ @@ -139,6 +150,19 @@ def __init__(self, *args, **kwargs): +""" + self.tau_half_pre222 = """ + + + + + + + + + + + """ # Actually generated from \[ a^3 + b^3 \neq c^3 \] tho self.fermat_hash = sha1("""\[ a^2 + b^2 = c^2 \]""".encode('utf-8')).digest() @@ -165,6 +189,30 @@ def __init__(self, *args, **kwargs): +""" + self.fermat_pre222 = """ + + + + + + + + + + + + + + + + + + + + + + """ # This is using the cache, so doesn't matter if LaTeX is found or not @@ -188,8 +236,8 @@ def test(self): self.fermat_hash: (6, 0.0, self.fermat)}) self.assertEqual(math_cache_actual, math_cache_expected) - @unittest.skipUnless(shutil.which('latex'), - "Math rendering requires LaTeX installed") + @unittest.skipUnless(shutil.which('latex') and LooseVersion(dvisvgm_version()) >= LooseVersion("2.2.2"), + "Math rendering requires LaTeX installed, dvisvgm < 2.2.2 has vastly different output") def test_uncached(self): # Write some bullshit there, which gets immediately reset with open(os.path.join(self.path, 'xml/math.cache'), 'wb') as f: @@ -216,6 +264,34 @@ def test_uncached(self): (0, 0.0, self.fermat)}) self.assertEqual(math_cache_actual, math_cache_expected) + @unittest.skipUnless(shutil.which('latex') and LooseVersion(dvisvgm_version()) < LooseVersion("2.2.2"), + "Math rendering requires LaTeX installed, dvisvgm < 2.2.2 has vastly different output") + def test_uncached_pre222(self): + # Write some bullshit there, which gets immediately reset + with open(os.path.join(self.path, 'xml/math.cache'), 'wb') as f: + pickle.dump((1337, 0, {"something different"}), f) + + self.run_dox2html5(wildcard='math-uncached.xml') + + with open(os.path.join(self.path, 'math-pre222.html')) as f: + expected_contents = f.read().strip() + # The file is the same expect for titles of the formulas. Replace them + # and then compare. + with open(os.path.join(self.path, 'html', 'math-uncached.html')) as f: + actual_contents = f.read().strip().replace('a^3 + b^3 \\neq c^3', 'a^2 + b^2 = c^2').replace('\\frac{\\tau}{2}', '\pi') + + self.assertEqual(actual_contents, expected_contents) + + # Expect that after the operation the global cache is filled + with open(os.path.join(self.path, 'xml/math.cache'), 'rb') as f: + math_cache_actual = pickle.load(f) + math_cache_expected = (0, 0, { + sha1("$ \\frac{\\tau}{2} $".encode('utf-8')).digest(): + (0, 0.3448408333333333, self.tau_half_pre222), + sha1("\\[ a^3 + b^3 \\neq c^3 \\]".encode('utf-8')).digest(): + (0, 0.0, self.fermat_pre222)}) + self.assertEqual(math_cache_actual, math_cache_expected) + def test_noop(self): if os.path.exists(os.path.join(self.path, 'xml/math.cache')): shutil.rmtree(os.path.join(self.path, 'xml/math.cache')) @@ -242,12 +318,18 @@ def test(self): self.run_dox2html5(wildcard='indexpage.xml') self.assertEqual(*self.actual_expected_contents('index.html')) - @unittest.skipUnless(shutil.which('latex'), - "Math rendering requires LaTeX installed") + @unittest.skipUnless(shutil.which('latex') and LooseVersion(dvisvgm_version()) >= LooseVersion("2.2.2"), + "Math rendering requires LaTeX installed, dvisvgm < 2.2.2 has vastly different output") def test_math(self): self.run_dox2html5(wildcard='math.xml') self.assertEqual(*self.actual_expected_contents('math.html')) + @unittest.skipUnless(shutil.which('latex') and LooseVersion(dvisvgm_version()) < LooseVersion("2.2.2"), + "Math rendering requires LaTeX installed, dvisvgm < 2.2.2 has vastly different output") + def test_math_pre222(self): + self.run_dox2html5(wildcard='math.xml') + self.assertEqual(*self.actual_expected_contents('math.html', 'math-pre222.html')) + @unittest.skipUnless(LooseVersion(dot_version()) >= LooseVersion("2.40.1"), "Dot < 2.40.1 has a completely different output.") def test_dot(self): diff --git a/package/ci/travis.yml b/package/ci/travis.yml index fe24cfea..578a43d3 100644 --- a/package/ci/travis.yml +++ b/package/ci/travis.yml @@ -17,6 +17,15 @@ matrix: apt: packages: - graphviz + - texlive-base + - texlive-latex-extra + - texlive-fonts-extra + - texlive-fonts-recommended + # it's only recommended by texlive-fonts-recommended (so Travis won't + # install it) but without it the math rendering blows up with + # ! Font TS1/ntxtlf/m/n/12=ts1-qtmr at 12.0pt not loadable: Metric (TFM) file not found. + # Wasted four hours on this damn thing. Ungoogleable errors FTW. + - tex-gyre env: - WITH_THEME=ON - WITH_DOXYGEN=OFF @@ -28,6 +37,15 @@ matrix: apt: packages: - graphviz + - texlive-base + - texlive-latex-extra + - texlive-fonts-extra + - texlive-fonts-recommended + # it's only recommended by texlive-fonts-recommended (so Travis won't + # install it) but without it the math rendering blows up with + # ! Font TS1/ntxtlf/m/n/12=ts1-qtmr at 12.0pt not loadable: Metric (TFM) file not found. + # Wasted four hours on this damn thing. Ungoogleable errors FTW. + - tex-gyre env: - WITH_THEME=ON - WITH_DOXYGEN=ON diff --git a/pelican-plugins/latex2svgextra.py b/pelican-plugins/latex2svgextra.py index e810f8b2..aa0702a0 100644 --- a/pelican-plugins/latex2svgextra.py +++ b/pelican-plugins/latex2svgextra.py @@ -81,7 +81,8 @@ ('fill=\'#cafe09\'', 'class=\'m-dim\'') } -_patch_src = re.compile(r"""<\?xml version='1\.0' encoding='UTF-8'\?> +# dvisvgm 1.9.2 doesn't put the encoding parameter there +_patch_src = re.compile(r"""<\?xml version='1\.0'( encoding='UTF-8')?\?> """) diff --git a/pelican-plugins/m/test/math/page-pre222.html b/pelican-plugins/m/test/math/page-pre222.html new file mode 100644 index 00000000..1d787607 --- /dev/null +++ b/pelican-plugins/m/test/math/page-pre222.html @@ -0,0 +1,374 @@ + + + + + m.math | A Pelican Blog + + + + + + +
+
+
+
+
+
+

m.math

+ +

Inline colored math + +a^2 + + + + + + + + + + and colored math block:

+
+ + +a^2 + b^2 = c^2 + + + + + + + + + + + + + + + + + + + +
+

Colored parts of inline + +b^2 - \color{m-info}{4ac} + + + + + + + + + + + + + + + + + + + + and block formulas:

+
+ + +\frac{-b \pm \color{m-success} \sqrt{D}}{2a} + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Properly align huge formulas vertically on a line: + + +\hat q^{-1} = \frac{\hat q^*}{|\hat q|^2} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +and make sure there's enough space for all the complex + +W + + + + + + + + things between +the lines + +W = \sum_{i=0}^{n} \frac{w_i}{h_i} + + + + + + + + + + + + + + + + + + + + + + + + + + + + because + + +Y = \sum_{i=0}^{n} B + + + + + + + + + + + + + + + + + + + + + +

+

The \cfrac thing doesn't align well: + +W = \sum_{i=0}^{n} \cfrac{w_i}{h_i} + + + + + + + + + + + + + + + + + + + + + + + + + + +

+

Properly escape the formula source:

+
+ + +\begin{array}{rcl} + x & = & 1 +\end{array} + + + + + + + + + + + +
+

Formulas + +a^2 + + + + + + + + + + in big text are big.

+

Formulas + +a^2 + + + + + + + + + + in small text are small.

+
+ + +a^2 + b^2 = c^2 + + + + + + + + + + + + + + + + + + + +
This is a title.
+

This is a description.

+
+
+ + +a^2 + b^2 = c^2 + + + + + + + + + + + + + + + + + + + +

The math below should not be styled as a part of the figure:

+
+ + +a^2 + b^2 = c^2 + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + diff --git a/pelican-plugins/m/test/math_cached/page-pre222.html b/pelican-plugins/m/test/math_cached/page-pre222.html new file mode 100644 index 00000000..5c438ab5 --- /dev/null +++ b/pelican-plugins/m/test/math_cached/page-pre222.html @@ -0,0 +1,75 @@ + + + + + Math | A Pelican Blog + + + + + + +
+
+
+
+
+
+

Math

+ +

In order to actually test use of the cache, I need to cheat a bit. Inline +formula which is pi in the source but + +\pi + + + + + + + + + + + here. Then a block +formula which is a Pythagorean theorem in source but not in the output:

+
+ + +a^2 + b^2 = c^2 + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+
+
+
+ + diff --git a/pelican-plugins/m/test/test_math.py b/pelican-plugins/m/test/test_math.py index b1b05c19..0603f356 100644 --- a/pelican-plugins/m/test/test_math.py +++ b/pelican-plugins/m/test/test_math.py @@ -26,6 +26,7 @@ import pickle import sys import shutil +import subprocess import unittest from hashlib import sha1 @@ -34,12 +35,17 @@ from . import PluginTestCase +def dvisvgm_version(): + # It's sometimes just "dvisvgm 2.3.5", other times + # "dvisvgm (TeX Live) 1.9.2", so use rpartition() + return subprocess.check_output(['dvisvgm', '--version'], stderr=subprocess.STDOUT).decode('utf-8').strip().rpartition(' ')[2] + class Math(PluginTestCase): def __init__(self, *args, **kwargs): super().__init__(__file__, '', *args, **kwargs) - @unittest.skipUnless(LooseVersion(sys.version) >= LooseVersion("3.5") and shutil.which('latex'), - "The math plugin requires at least Python 3.5 and LaTeX installed") + @unittest.skipUnless(LooseVersion(sys.version) >= LooseVersion("3.5") and shutil.which('latex') and LooseVersion(dvisvgm_version()) >= LooseVersion("2.2.2"), + "The math plugin requires at least Python 3.5 and LaTeX installed, dvisvgm < 2.2.2 has vastly different output") def test(self): self.run_pelican({ 'PLUGINS': ['m.htmlsanity', 'm.components', 'm.math'], @@ -51,6 +57,19 @@ def test(self): # No file should be generated when math caching is disabled self.assertFalse(os.path.exists(os.path.join(self.path, 'm.math.cache'))) + @unittest.skipUnless(LooseVersion(sys.version) >= LooseVersion("3.5") and shutil.which('latex') and LooseVersion(dvisvgm_version()) < LooseVersion("2.2.2"), + "The math plugin requires at least Python 3.5 and LaTeX installed, dvisvgm < 2.2.2 has vastly different output") + def test_pre222(self): + self.run_pelican({ + 'PLUGINS': ['m.htmlsanity', 'm.components', 'm.math'], + 'M_MATH_CACHE_FILE': None + }) + + self.assertEqual(*self.actual_expected_contents('page.html', 'page-pre222.html')) + + # No file should be generated when math caching is disabled + self.assertFalse(os.path.exists(os.path.join(self.path, 'm.math.cache'))) + def test_code_fallback(self): self.run_pelican({ 'PLUGINS': ['m.htmlsanity', 'm.math'], @@ -77,6 +96,19 @@ def test_code_fallback(self): """ +tau_half_pre222 = """ + + + + + + + + + + + +""" # Actually generated from $$a^3 + b^3 \neq c^3$$ tho fermat_hash = sha1("""$$a^2 + b^2 = c^2$$""".encode('utf-8')).digest() @@ -104,6 +136,30 @@ def test_code_fallback(self): """ +fermat_pre222 = """ + + + + + + + + + + + + + + + + + + + + + + +""" class Cached(PluginTestCase): def __init__(self, *args, **kwargs): @@ -140,8 +196,8 @@ class Uncached(PluginTestCase): def __init__(self, *args, **kwargs): super().__init__(__file__, 'uncached', *args, **kwargs) - @unittest.skipUnless(shutil.which('latex'), - "Math rendering requires LaTeX installed") + @unittest.skipUnless(shutil.which('latex') and LooseVersion(dvisvgm_version()) >= LooseVersion("2.2.2"), + "Math rendering requires LaTeX installed, dvisvgm < 2.2.2 has vastly different output") def test(self): cache_file = os.path.join(self.path, 'math.cache') @@ -172,3 +228,36 @@ def test(self): sha1("$$a^3 + b^3 \\neq c^3$$".encode('utf-8')).digest(): (0, 0.0, fermat)}) self.assertEqual(math_cache_actual, math_cache_expected) + + @unittest.skipUnless(shutil.which('latex') and LooseVersion(dvisvgm_version()) < LooseVersion("2.2.2"), + "Math rendering requires LaTeX installed, dvisvgm < 2.2.2 has vastly different output") + def test_pre222(self): + cache_file = os.path.join(self.path, 'math.cache') + + # Write some bullshit there, which gets immediately reset + with open(cache_file, 'wb') as f: + pickle.dump((1337, 0, {"something different"}), f) + + self.run_pelican({ + 'PLUGINS': ['m.htmlsanity', 'm.math'], + 'M_MATH_CACHE_FILE': cache_file + }) + + with open(os.path.join(self.path, '../math_cached/page-pre222.html')) as f: + expected_contents = f.read().strip() + # The file is the same expect for titles of the formulas. Replace them + # and then compare. + with open(os.path.join(self.path, 'output', 'page.html')) as f: + actual_contents = f.read().strip().replace('a^3 + b^3 \\neq c^3', 'a^2 + b^2 = c^2').replace('\\frac{\\tau}{2}', '\pi') + + self.assertEqual(actual_contents, expected_contents) + + # Expect that after the operation the global cache is filled + with open(cache_file, 'rb') as f: + math_cache_actual = pickle.load(f) + math_cache_expected = (0, 0, { + sha1("$\\frac{\\tau}{2}$".encode('utf-8')).digest(): + (0, 0.3448408333333333, tau_half_pre222), + sha1("$$a^3 + b^3 \\neq c^3$$".encode('utf-8')).digest(): + (0, 0.0, fermat_pre222)}) + self.assertEqual(math_cache_actual, math_cache_expected)