summaryrefslogtreecommitdiff
path: root/app/src/test/java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/test/java')
-rw-r--r--app/src/test/java/org/terst/feedreader/readability/ExtractionFailureTest.kt82
1 files changed, 82 insertions, 0 deletions
diff --git a/app/src/test/java/org/terst/feedreader/readability/ExtractionFailureTest.kt b/app/src/test/java/org/terst/feedreader/readability/ExtractionFailureTest.kt
new file mode 100644
index 0000000..6f691fd
--- /dev/null
+++ b/app/src/test/java/org/terst/feedreader/readability/ExtractionFailureTest.kt
@@ -0,0 +1,82 @@
+package org.terst.feedreader.readability
+
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+/**
+ * Extraction failures used to be discarded entirely — ReaderScreen did
+ * `extracted?.content?.let { }`, so any failure left the reader silently showing
+ * the raw feed content. The bug report that prompted this could say only
+ * "extraction failed", because the app itself never knew why.
+ *
+ * These pin the two things a failure has to produce: something short enough to
+ * put in front of the user, and something specific enough to debug from.
+ */
+class ExtractionFailureTest {
+
+ @Test
+ fun `load error names the underlying description`() {
+ val f = ExtractionFailure.LoadError(-2, "net::ERR_NAME_NOT_RESOLVED")
+ assertEquals("Couldn't load the page (net::ERR_NAME_NOT_RESOLVED)", f.userMessage())
+ assertTrue(f.diagnostic().contains("code=-2"))
+ assertTrue(f.diagnostic().contains("ERR_NAME_NOT_RESOLVED"))
+ }
+
+ @Test
+ fun `load error without a description still reads properly`() {
+ assertEquals("Couldn't load the page", ExtractionFailure.LoadError(-1, null).userMessage())
+ assertEquals("Couldn't load the page", ExtractionFailure.LoadError(-1, " ").userMessage())
+ }
+
+ @Test
+ fun `http error names the status`() {
+ val f = ExtractionFailure.HttpError(403, "Forbidden")
+ assertEquals("Server returned HTTP 403", f.userMessage())
+ assertTrue(f.diagnostic().contains("status=403"))
+ }
+
+ @Test
+ fun `timeout is reported in seconds`() {
+ assertEquals("Page took longer than 25s to load", ExtractionFailure.TimedOut(25_000).userMessage())
+ assertTrue(ExtractionFailure.TimedOut(25_000).diagnostic().contains("25000ms"))
+ }
+
+ @Test
+ fun `readability error carries the thrown message`() {
+ val f = ExtractionFailure.ReadabilityError("TypeError: x is null")
+ assertTrue(f.userMessage().contains("TypeError"))
+ assertTrue(f.diagnostic().contains("TypeError"))
+ }
+
+ @Test
+ fun `no content is distinct from an error`() {
+ assertEquals("No article text found on the page", ExtractionFailure.NoContent.userMessage())
+ }
+
+ // The raw JS result can be enormous; a diagnostic that pastes all of it is
+ // unusable in a bug report.
+ @Test
+ fun `bad result truncates the raw payload`() {
+ val f = ExtractionFailure.BadResult("x".repeat(5_000))
+ assertTrue("diagnostic should be bounded", f.diagnostic().length < 400)
+ }
+
+ // Every case must produce a non-empty message; a blank one would put the
+ // user back where they started.
+ @Test
+ fun `every failure produces both messages`() {
+ val all = listOf(
+ ExtractionFailure.LoadError(-6, "ERR_CONNECTION_REFUSED"),
+ ExtractionFailure.HttpError(500, null),
+ ExtractionFailure.TimedOut(25_000),
+ ExtractionFailure.ReadabilityError("boom"),
+ ExtractionFailure.NoContent,
+ ExtractionFailure.BadResult("{}"),
+ )
+ for (f in all) {
+ assertTrue("$f has a blank user message", f.userMessage().isNotBlank())
+ assertTrue("$f has a blank diagnostic", f.diagnostic().isNotBlank())
+ }
+ }
+}