mirror of https://github.com/readrops/Readrops.git
Some Nextcloud News item fields can be null
This commit is contained in:
parent
6e1dbc789c
commit
7701cebdba
|
@ -3,13 +3,14 @@ package com.readrops.api.services.nextcloudnews.adapters
|
|||
import android.annotation.SuppressLint
|
||||
import com.readrops.api.utils.ApiUtils
|
||||
import com.readrops.api.utils.exceptions.ParseException
|
||||
import com.readrops.api.utils.extensions.nextNonEmptyString
|
||||
import com.readrops.api.utils.extensions.nextNullableLong
|
||||
import com.readrops.api.utils.extensions.nextNullableString
|
||||
import com.readrops.db.entities.Item
|
||||
import com.readrops.db.util.DateUtils
|
||||
import com.squareup.moshi.JsonAdapter
|
||||
import com.squareup.moshi.JsonReader
|
||||
import com.squareup.moshi.JsonWriter
|
||||
import java.time.LocalDateTime
|
||||
|
||||
class NextcloudNewsItemsAdapter : JsonAdapter<List<Item>>() {
|
||||
|
||||
|
@ -39,9 +40,18 @@ class NextcloudNewsItemsAdapter : JsonAdapter<List<Item>>() {
|
|||
when (reader.selectName(NAMES)) {
|
||||
0 -> remoteId = reader.nextInt().toString()
|
||||
1 -> link = reader.nextNullableString()
|
||||
2 -> title = reader.nextNonEmptyString()
|
||||
2 -> title = reader.nextNullableString()
|
||||
3 -> author = reader.nextNullableString()
|
||||
4 -> pubDate = DateUtils.fromEpochSeconds(reader.nextLong())
|
||||
4 -> {
|
||||
val value = reader.nextNullableLong()
|
||||
|
||||
pubDate = if (value != null) {
|
||||
DateUtils.fromEpochSeconds(value)
|
||||
} else {
|
||||
LocalDateTime.now()
|
||||
}
|
||||
}
|
||||
|
||||
5 -> content = reader.nextNullableString()
|
||||
6 -> enclosureMime = reader.nextNullableString()
|
||||
7 -> enclosureLink = reader.nextNullableString()
|
||||
|
@ -53,10 +63,14 @@ class NextcloudNewsItemsAdapter : JsonAdapter<List<Item>>() {
|
|||
}
|
||||
}
|
||||
|
||||
if (enclosureMime != null && ApiUtils.isMimeImage(enclosureMime!!))
|
||||
if (enclosureMime != null && ApiUtils.isMimeImage(enclosureMime!!)) {
|
||||
item.imageLink = enclosureLink
|
||||
}
|
||||
|
||||
if (item.title != null) {
|
||||
items += item
|
||||
}
|
||||
|
||||
items += item
|
||||
reader.endObject()
|
||||
}
|
||||
|
||||
|
@ -70,7 +84,9 @@ class NextcloudNewsItemsAdapter : JsonAdapter<List<Item>>() {
|
|||
}
|
||||
|
||||
companion object {
|
||||
val NAMES: JsonReader.Options = JsonReader.Options.of("id", "url", "title", "author",
|
||||
"pubDate", "body", "enclosureMime", "enclosureLink", "feedId", "unread", "starred")
|
||||
val NAMES: JsonReader.Options = JsonReader.Options.of(
|
||||
"id", "url", "title", "author",
|
||||
"pubDate", "body", "enclosureMime", "enclosureLink", "feedId", "unread", "starred"
|
||||
)
|
||||
}
|
||||
}
|
|
@ -14,6 +14,9 @@ fun JsonReader.nextNonEmptyString(): String {
|
|||
fun JsonReader.nextNullableInt(): Int? =
|
||||
if (peek() != JsonReader.Token.NULL) nextInt() else nextNull()
|
||||
|
||||
fun JsonReader.nextNullableLong(): Long? =
|
||||
if (peek() != JsonReader.Token.NULL) nextLong() else nextNull()
|
||||
|
||||
fun JsonReader.skipField() {
|
||||
skipName()
|
||||
skipValue()
|
||||
|
|
|
@ -4,11 +4,16 @@ import com.readrops.api.TestUtils
|
|||
import com.readrops.api.apiModule
|
||||
import com.readrops.api.enqueueOK
|
||||
import com.readrops.api.enqueueStream
|
||||
import com.readrops.api.okResponseWithBody
|
||||
import com.readrops.api.services.SyncType
|
||||
import com.readrops.db.entities.account.Account
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import okhttp3.mockwebserver.Dispatcher
|
||||
import okhttp3.mockwebserver.MockResponse
|
||||
import okhttp3.mockwebserver.MockWebServer
|
||||
import okhttp3.mockwebserver.RecordedRequest
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
|
@ -93,12 +98,18 @@ class NextcloudNewsDataSourceTest : KoinTest {
|
|||
val stream = TestUtils.loadResource("services/nextcloudnews/adapters/items.json")
|
||||
mockServer.enqueueStream(stream)
|
||||
|
||||
val items = nextcloudNewsDataSource.getItems(NextcloudNewsDataSource.ItemQueryType.ALL.value, false, 10)
|
||||
val type = NextcloudNewsDataSource.ItemQueryType.ALL.value
|
||||
|
||||
val items = nextcloudNewsDataSource.getItems(
|
||||
type = type,
|
||||
read = false,
|
||||
batchSize = 10
|
||||
)
|
||||
val request = mockServer.takeRequest()
|
||||
|
||||
assertTrue { items.size == 3 }
|
||||
assertTrue { items.size == 2 }
|
||||
with(request.requestUrl!!) {
|
||||
assertEquals("3", queryParameter("type"))
|
||||
assertEquals("$type", queryParameter("type"))
|
||||
assertEquals("false", queryParameter("getRead"))
|
||||
assertEquals("10", queryParameter("batchSize"))
|
||||
}
|
||||
|
@ -113,7 +124,7 @@ class NextcloudNewsDataSourceTest : KoinTest {
|
|||
nextcloudNewsDataSource.getNewItems(1512, NextcloudNewsDataSource.ItemQueryType.ALL)
|
||||
val request = mockServer.takeRequest()
|
||||
|
||||
assertTrue { items.size == 3 }
|
||||
assertTrue { items.size == 2 }
|
||||
with(request.requestUrl!!) {
|
||||
assertEquals("1512", queryParameter("lastModified"))
|
||||
assertEquals("3", queryParameter("type"))
|
||||
|
@ -125,13 +136,13 @@ class NextcloudNewsDataSourceTest : KoinTest {
|
|||
val stream = TestUtils.loadResource("services/nextcloudnews/adapters/feeds.json")
|
||||
mockServer.enqueueStream(stream)
|
||||
|
||||
val feeds = nextcloudNewsDataSource.createFeed("https://news.ycombinator.com/rss", null)
|
||||
val feeds = nextcloudNewsDataSource.createFeed("https://news.ycombinator.com/rss", 100)
|
||||
val request = mockServer.takeRequest()
|
||||
|
||||
assertTrue { feeds.isNotEmpty() }
|
||||
with(request.requestUrl!!) {
|
||||
assertEquals("https://news.ycombinator.com/rss", queryParameter("url"))
|
||||
assertEquals(null, queryParameter("folderId"))
|
||||
assertEquals("100", queryParameter("folderId"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,12 +163,11 @@ class NextcloudNewsDataSourceTest : KoinTest {
|
|||
nextcloudNewsDataSource.changeFeedFolder(15, 18)
|
||||
val request = mockServer.takeRequest()
|
||||
|
||||
val type =
|
||||
Types.newParameterizedType(
|
||||
Map::class.java,
|
||||
String::class.java,
|
||||
Int::class.javaObjectType
|
||||
)
|
||||
val type = Types.newParameterizedType(
|
||||
Map::class.java,
|
||||
String::class.java,
|
||||
Int::class.javaObjectType
|
||||
)
|
||||
val adapter = moshi.adapter<Map<String, Int>>(type)
|
||||
val body = adapter.fromJson(request.body)!!
|
||||
|
||||
|
@ -267,12 +277,11 @@ class NextcloudNewsDataSourceTest : KoinTest {
|
|||
val starRequest = mockServer.takeRequest()
|
||||
val unstarRequest = mockServer.takeRequest()
|
||||
|
||||
val type =
|
||||
Types.newParameterizedType(
|
||||
Map::class.java,
|
||||
String::class.java,
|
||||
Types.newParameterizedType(List::class.java, Int::class.javaObjectType)
|
||||
)
|
||||
val type = Types.newParameterizedType(
|
||||
Map::class.java,
|
||||
String::class.java,
|
||||
Types.newParameterizedType(List::class.java, Int::class.javaObjectType)
|
||||
)
|
||||
val adapter = moshi.adapter<Map<String, List<Int>>>(type)
|
||||
|
||||
val starBody = adapter.fromJson(starRequest.body)!!
|
||||
|
@ -281,4 +290,100 @@ class NextcloudNewsDataSourceTest : KoinTest {
|
|||
assertEquals(data.starredIds, starBody["itemIds"])
|
||||
assertEquals(data.unstarredIds, unstarBody["itemIds"])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun initialSyncTest() = runTest {
|
||||
mockServer.dispatcher = object : Dispatcher() {
|
||||
|
||||
override fun dispatch(request: RecordedRequest): MockResponse {
|
||||
with(request.path!!) {
|
||||
return when {
|
||||
this == "/folders" -> {
|
||||
MockResponse.okResponseWithBody(TestUtils.loadResource("services/nextcloudnews/adapters/valid_folder.json"))
|
||||
}
|
||||
|
||||
this == "/feeds" -> {
|
||||
MockResponse.okResponseWithBody(TestUtils.loadResource("services/nextcloudnews/adapters/feeds.json"))
|
||||
}
|
||||
|
||||
contains("/items") -> {
|
||||
|
||||
MockResponse.okResponseWithBody(TestUtils.loadResource("services/nextcloudnews/adapters/items.json"))
|
||||
}
|
||||
|
||||
else -> MockResponse().setResponseCode(404)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val result =
|
||||
nextcloudNewsDataSource.synchronize(SyncType.INITIAL_SYNC, NextcloudNewsSyncData())
|
||||
|
||||
with(result) {
|
||||
assertEquals(1, folders.size)
|
||||
assertEquals(3, feeds.size)
|
||||
assertEquals(2, items.size)
|
||||
assertEquals(2, starredItems.size)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun classicSyncTest() = runTest {
|
||||
var setItemState = 0
|
||||
val lastModified = 10L
|
||||
val ids = listOf(1, 2, 3, 4)
|
||||
|
||||
mockServer.dispatcher = object : Dispatcher() {
|
||||
|
||||
override fun dispatch(request: RecordedRequest): MockResponse {
|
||||
with(request.path!!) {
|
||||
// important, otherwise test fails and I don't know why
|
||||
println("request: ${request.path}")
|
||||
return when {
|
||||
this == "/folders" -> {
|
||||
MockResponse.okResponseWithBody(TestUtils.loadResource("services/nextcloudnews/adapters/valid_folder.json"))
|
||||
}
|
||||
|
||||
this == "/feeds" -> {
|
||||
MockResponse.okResponseWithBody(TestUtils.loadResource("services/nextcloudnews/adapters/feeds.json"))
|
||||
}
|
||||
|
||||
contains("/items/updated") -> {
|
||||
assertEquals(
|
||||
"$lastModified",
|
||||
request.requestUrl!!.queryParameter("lastModified")
|
||||
)
|
||||
MockResponse.okResponseWithBody(TestUtils.loadResource("services/nextcloudnews/adapters/items.json"))
|
||||
}
|
||||
|
||||
this.matches(Regex("/items/(read|unread|star|unstar)/multiple")) -> {
|
||||
setItemState++
|
||||
MockResponse().setResponseCode(200)
|
||||
}
|
||||
|
||||
else -> MockResponse().setResponseCode(404)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val result = nextcloudNewsDataSource.synchronize(
|
||||
SyncType.CLASSIC_SYNC,
|
||||
NextcloudNewsSyncData(
|
||||
lastModified = lastModified,
|
||||
readIds = ids,
|
||||
unreadIds = ids,
|
||||
starredIds = ids,
|
||||
unstarredIds = ids
|
||||
)
|
||||
)
|
||||
|
||||
with(result) {
|
||||
assertEquals(4, setItemState)
|
||||
assertEquals(1, folders.size)
|
||||
assertEquals(3, feeds.size)
|
||||
assertEquals(2, items.size)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,7 +21,9 @@ class NextcloudNewsItemsAdapterTest {
|
|||
val stream = TestUtils.loadResource("services/nextcloudnews/adapters/items.json")
|
||||
|
||||
val items = adapter.fromJson(Buffer().readFrom(stream))!!
|
||||
val item = items[0]
|
||||
val item = items.first()
|
||||
|
||||
assertEquals(2, items.size)
|
||||
|
||||
with(item) {
|
||||
assertEquals(remoteId, "3443")
|
||||
|
@ -33,11 +35,11 @@ class NextcloudNewsItemsAdapterTest {
|
|||
assertEquals(isRead, false)
|
||||
assertEquals(isStarred, false)
|
||||
assertEquals(pubDate, DateUtils.fromEpochSeconds(1367270544))
|
||||
assertEquals(imageLink, null)
|
||||
assertEquals(imageLink, "https://test.org/image.jpg")
|
||||
}
|
||||
|
||||
with(items[1]) {
|
||||
assertEquals(imageLink, "https://test.org/image.jpg")
|
||||
assertEquals(imageLink, null)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.readrops.api.utils
|
|||
|
||||
import com.readrops.api.utils.exceptions.ParseException
|
||||
import com.readrops.api.utils.extensions.nextNonEmptyString
|
||||
import com.readrops.api.utils.extensions.nextNullableLong
|
||||
import com.readrops.api.utils.extensions.nextNullableString
|
||||
import com.squareup.moshi.JsonReader
|
||||
import junit.framework.TestCase.assertEquals
|
||||
|
@ -85,4 +86,33 @@ class JsonReaderExtensionsTest {
|
|||
reader.nextNonEmptyString()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun nextNullableLongNormalCaseTest() {
|
||||
val reader = JsonReader.of(Buffer().readFrom("""
|
||||
{
|
||||
"field": "5555555555555555555"
|
||||
}
|
||||
""".trimIndent().byteInputStream()))
|
||||
|
||||
reader.beginObject()
|
||||
reader.nextName()
|
||||
|
||||
assertEquals(5555555555555555555L, reader.nextNullableLong())
|
||||
reader.endObject()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun nextNullableLongNullCaseTest() {
|
||||
val reader = JsonReader.of(Buffer().readFrom("""
|
||||
{
|
||||
"field": null
|
||||
}
|
||||
""".trimIndent().byteInputStream()))
|
||||
|
||||
reader.beginObject()
|
||||
reader.nextName()
|
||||
|
||||
assertNull(reader.nextNullableLong())
|
||||
reader.endObject()
|
||||
}
|
||||
}
|
|
@ -9,8 +9,8 @@
|
|||
"author": "Jan Grulich (grulja)",
|
||||
"pubDate": 1367270544,
|
||||
"body": "<p>At first I have to say...</p>",
|
||||
"enclosureMime": null,
|
||||
"enclosureLink": null,
|
||||
"enclosureMime": "image",
|
||||
"enclosureLink": "https://test.org/image.jpg",
|
||||
"mediaThumbnail": null,
|
||||
"mediaDescription": null,
|
||||
"feedId": 67,
|
||||
|
@ -25,12 +25,12 @@
|
|||
"guid": "http://grulja.wordpress.com/?p=76",
|
||||
"guidHash": "3059047a572cd9cd5d0bf645faffd077",
|
||||
"url": "http://grulja.wordpress.com/2013/04/29/plasma-nm-after-the-solid-sprint/",
|
||||
"title": "Plasma-nm after the solid sprint",
|
||||
"title": "",
|
||||
"author": "Jan Grulich (grulja)",
|
||||
"pubDate": 1367270544,
|
||||
"body": "<p>At first I have to say...</p>",
|
||||
"enclosureMime": "image",
|
||||
"enclosureLink": "https://test.org/image.jpg",
|
||||
"enclosureMime": null,
|
||||
"enclosureLink": null,
|
||||
"mediaThumbnail": null,
|
||||
"mediaDescription": null,
|
||||
"feedId": 67,
|
||||
|
|
Loading…
Reference in New Issue