diff options
Diffstat (limited to 'app/src/test/java/org/terst/feedreader/readability/UnrenderedTexTest.kt')
| -rw-r--r-- | app/src/test/java/org/terst/feedreader/readability/UnrenderedTexTest.kt | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/app/src/test/java/org/terst/feedreader/readability/UnrenderedTexTest.kt b/app/src/test/java/org/terst/feedreader/readability/UnrenderedTexTest.kt new file mode 100644 index 0000000..016b148 --- /dev/null +++ b/app/src/test/java/org/terst/feedreader/readability/UnrenderedTexTest.kt @@ -0,0 +1,116 @@ +package org.terst.feedreader.readability + +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test + +/** + * Recognising a cached extraction that still holds raw TeX source. + * + * Substack ships maths as TeX source text in the page (`\(p = \text{...}\)` inside a + * `latex-rendered` wrapper) and renders it client-side with its own script, which never + * runs in this app. Extraction now converts that source to MathML before Readability sees + * it -- but an article extracted BEFORE that existed has the raw source sitting in + * `articles.extractedContent`, and every subsequent open reads it straight back out. The + * reported article came with "extractedContent cached: true", so this is the half a fixed + * extractor cannot reach. + * + * Over-detecting is the real risk: a false positive makes the article re-extract on every + * single open, since re-extracting cannot change a verdict the content itself causes. So + * the bar is a complete delimiter pair around something that actually looks like TeX, and + * never anything already carrying rendered MathML. + */ +class UnrenderedTexTest { + + // "$$" cannot be written inline in a Kotlin string followed by a letter -- that parses + // as a template expression. + private val dollars = "$" + "$" + + @Test + fun `substack's inline-delimited tex source is recognised`() { + assertTrue( + UnrenderedTex.looksLikeUnrenderedTex( + "<div data-component-name=\"Latex\"><p><span>" + + "\\(p = \\text{“if }p\\text{ is true, then pigs can fly”}\\)</span></p></div>" + ) + ) + } + + @Test + fun `bracket-delimited display tex source is recognised`() { + assertTrue(UnrenderedTex.looksLikeUnrenderedTex("<p>\\[\\begin{align} a &= b \\end{align}\\]</p>")) + } + + @Test + fun `double-dollar display tex source is recognised`() { + assertTrue(UnrenderedTex.looksLikeUnrenderedTex("<p>" + dollars + "x_{1} + y^{2}" + dollars + "</p>")) + } + + @Test + fun `content already carrying rendered mathml is left alone`() { + assertFalse( + UnrenderedTex.looksLikeUnrenderedTex( + "<p><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><mi>p</mi></math></p>" + ) + ) + } + + // An expression KaTeX could not render stays in the output as source. If the presence of + // any source at all convicted the whole article, that article would re-extract on every + // open, for ever, and never come out any different. Rendered maths anywhere in the + // content is proof the extraction already had its go at it. + @Test + fun `a leftover unrenderable expression alongside rendered mathml does not convict`() { + assertFalse( + UnrenderedTex.looksLikeUnrenderedTex( + "<p><math><mi>a</mi></math></p><p>\\(\\thisIsNotRealTex{}\\)</p>" + ) + ) + } + + @Test + fun `ordinary prose is not tex`() { + assertFalse( + UnrenderedTex.looksLikeUnrenderedTex( + "<p>The repair bill came to $$ in the end; the second quote was $$ as well, and (as it " + + "turned out) the warranty had lapsed anyway.</p>" + ) + ) + } + + // The inner span between two stray delimiters is HTML, not one expression -- markup + // brings its own underscores and braces along (ids, filenames, inline styles), so a tag + // anywhere inside is on its own enough to say these two delimiters are unrelated. + @Test + fun `delimiters spanning real markup are not one expression`() { + assertFalse( + UnrenderedTex.looksLikeUnrenderedTex( + "<p>It cost $$ for the <a href=\"https://ex.com/part_no_4.html\">part</a>, " + + "and $$ again for the labour.</p>" + ) + ) + } + + @Test + fun `an unclosed delimiter is not tex`() { + assertFalse(UnrenderedTex.looksLikeUnrenderedTex("<p>Then he wrote \\(x, trailed off, and left.</p>")) + } + + // Extraction deliberately skips <pre>/<code> when rendering maths -- an article ABOUT + // TeX quotes the source on purpose. Convicting on that would re-extract it on every + // open and still, correctly, change nothing. + @Test + fun `tex quoted inside a code block is not a stale extraction`() { + assertFalse( + UnrenderedTex.looksLikeUnrenderedTex( + "<p>Write it like this:</p><pre><code>\\(x^{2} + y^{2}\\)</code></pre>" + ) + ) + } + + @Test + fun `nothing cached is not tex`() { + assertFalse(UnrenderedTex.looksLikeUnrenderedTex(null)) + assertFalse(UnrenderedTex.looksLikeUnrenderedTex(" ")) + } +} |
