summaryrefslogtreecommitdiff
path: root/app/src/test/java/org/terst/feedreader/readability/EvalOutcomeTest.kt
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/test/java/org/terst/feedreader/readability/EvalOutcomeTest.kt')
-rw-r--r--app/src/test/java/org/terst/feedreader/readability/EvalOutcomeTest.kt89
1 files changed, 89 insertions, 0 deletions
diff --git a/app/src/test/java/org/terst/feedreader/readability/EvalOutcomeTest.kt b/app/src/test/java/org/terst/feedreader/readability/EvalOutcomeTest.kt
new file mode 100644
index 0000000..8995e22
--- /dev/null
+++ b/app/src/test/java/org/terst/feedreader/readability/EvalOutcomeTest.kt
@@ -0,0 +1,89 @@
+package org.terst.feedreader.readability
+
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+/**
+ * The decision ReaderExtractor makes about each `evaluateJavascript` result:
+ * accept it, inject again because the page probably was not ready, or give up
+ * with a reason. It used to live inline in a WebView callback, which meant the
+ * only way to exercise it was on a device against a live page.
+ *
+ * The case that mattered and was never covered: a result that is perfectly
+ * well-formed and non-blank, and is the page's cookie-consent banner rather than
+ * the article. That counted as a success, got cached, and stayed cached.
+ */
+class EvalOutcomeTest {
+
+ private val maxAttempts = 6
+
+ private fun decide(article: ExtractedArticle?, attempt: Int, raw: String = "\"{}\"") =
+ decideEvalOutcome(article, raw, attempt, maxAttempts)
+
+ private fun article(content: String?, error: String? = null) =
+ ExtractedArticle(title = "t", content = content, textContent = content, error = error)
+
+ @Test
+ fun `real content is accepted on the first attempt`() {
+ val a = article("<p>" + "The actual article body. ".repeat(60) + "</p>")
+ val decision = decide(a, attempt = 1)
+ assertEquals(EvalDecision.Done(ExtractionResult.Success(a)), decision)
+ }
+
+ // Retrying cannot change Readability's opinion of the markup, so a thrown
+ // error is final however early it arrives.
+ @Test
+ fun `a readability error is final immediately`() {
+ val decision = decide(article(null, error = "TypeError: x is null"), attempt = 1)
+ assertEquals(
+ EvalDecision.Done(ExtractionResult.Failure(ExtractionFailure.ReadabilityError("TypeError: x is null"))),
+ decision
+ )
+ }
+
+ @Test
+ fun `an undecodable result retries and then reports a bad result`() {
+ assertEquals(EvalDecision.Retry, decide(null, attempt = 1, raw = "null"))
+ val last = decide(null, attempt = maxAttempts, raw = "null")
+ assertEquals(EvalDecision.Done(ExtractionResult.Failure(ExtractionFailure.BadResult("null"))), last)
+ }
+
+ @Test
+ fun `blank content retries and then reports no content`() {
+ assertEquals(EvalDecision.Retry, decide(article(""), attempt = 1))
+ assertEquals(
+ EvalDecision.Done(ExtractionResult.Failure(ExtractionFailure.NoContent)),
+ decide(article(""), attempt = maxAttempts)
+ )
+ }
+
+ // A cookie banner is exactly what a half-loaded page yields -- the banner is
+ // injected early, the article body may not be in the DOM yet -- so the right
+ // first move is the retry the extractor already does for an empty result.
+ @Test
+ fun `a consent notice retries rather than being accepted`() {
+ val decision = decide(article(ConsentNoticeTest.EXTRACTED_COOKIE_NOTICE), attempt = 1)
+ assertEquals(EvalDecision.Retry, decision)
+ }
+
+ @Test
+ fun `a consent notice that survives every attempt is reported as a failure`() {
+ val decision = decide(article(ConsentNoticeTest.EXTRACTED_COOKIE_NOTICE), attempt = maxAttempts)
+ assertEquals(
+ EvalDecision.Done(ExtractionResult.Failure(ExtractionFailure.ConsentInterstitial)),
+ decision
+ )
+ }
+
+ // The failure has to be distinguishable from "no content": one means the page
+ // has no article, the other means the page would not show it without consent.
+ @Test
+ fun `the consent failure says what happened`() {
+ val f: ExtractionFailure = ExtractionFailure.ConsentInterstitial
+ assertTrue(f.userMessage().isNotBlank())
+ assertTrue(f.diagnostic().isNotBlank())
+ assertTrue(f.userMessage().lowercase().contains("cookie") || f.userMessage().lowercase().contains("consent"))
+ assertTrue(f.userMessage() != ExtractionFailure.NoContent.userMessage())
+ }
+}