1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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(" "))
}
}
|