fix: Prevent crash when Friendica returns a null `voted_on` property (#456)
Friendica can return a null `voted_on` property, in violation of the API spec. Introduce a `BooleanIfNull` annotation that will convert the `null` to `false` if encountered. While I'm here update the other adapters as classes on their relevant annotations instead of standalone classes to keep the code consistent. Fixes #455
This commit is contained in:
parent
23e3cf1035
commit
73c947edfa
|
@ -2,8 +2,9 @@ package app.pachli
|
|||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import app.pachli.core.database.model.TranslationState
|
||||
import app.pachli.core.network.json.DefaultIfNullAdapter.Companion.DefaultIfNullAdapterFactory
|
||||
import app.pachli.core.network.json.GuardedAdapter.Companion.GuardedAdapterFactory
|
||||
import app.pachli.core.network.json.BooleanIfNull
|
||||
import app.pachli.core.network.json.DefaultIfNull
|
||||
import app.pachli.core.network.json.Guarded
|
||||
import app.pachli.core.network.model.Status
|
||||
import app.pachli.viewdata.StatusViewData
|
||||
import com.squareup.moshi.Moshi
|
||||
|
@ -19,8 +20,9 @@ import org.junit.runner.RunWith
|
|||
class StatusComparisonTest {
|
||||
private val moshi = Moshi.Builder()
|
||||
.add(Date::class.java, Rfc3339DateJsonAdapter())
|
||||
.add(GuardedAdapterFactory())
|
||||
.add(DefaultIfNullAdapterFactory())
|
||||
.add(Guarded.Factory())
|
||||
.add(DefaultIfNull.Factory())
|
||||
.add(BooleanIfNull.Factory())
|
||||
.build()
|
||||
|
||||
@Test
|
||||
|
|
|
@ -20,8 +20,9 @@ import app.pachli.core.database.model.AccountEntity
|
|||
import app.pachli.core.database.model.RemoteKeyEntity
|
||||
import app.pachli.core.database.model.RemoteKeyKind
|
||||
import app.pachli.core.database.model.TimelineStatusWithAccount
|
||||
import app.pachli.core.network.json.DefaultIfNullAdapter.Companion.DefaultIfNullAdapterFactory
|
||||
import app.pachli.core.network.json.GuardedAdapter.Companion.GuardedAdapterFactory
|
||||
import app.pachli.core.network.json.BooleanIfNull
|
||||
import app.pachli.core.network.json.DefaultIfNull
|
||||
import app.pachli.core.network.json.Guarded
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.adapters.Rfc3339DateJsonAdapter
|
||||
|
@ -66,8 +67,9 @@ class CachedTimelineRemoteMediatorTest {
|
|||
|
||||
private val moshi: Moshi = Moshi.Builder()
|
||||
.add(Date::class.java, Rfc3339DateJsonAdapter())
|
||||
.add(GuardedAdapterFactory())
|
||||
.add(DefaultIfNullAdapterFactory())
|
||||
.add(Guarded.Factory())
|
||||
.add(DefaultIfNull.Factory())
|
||||
.add(BooleanIfNull.Factory())
|
||||
.build()
|
||||
|
||||
@Before
|
||||
|
|
|
@ -5,8 +5,9 @@ import app.pachli.core.database.model.TimelineAccountEntity
|
|||
import app.pachli.core.database.model.TimelineStatusEntity
|
||||
import app.pachli.core.database.model.TimelineStatusWithAccount
|
||||
import app.pachli.core.database.model.TranslationState
|
||||
import app.pachli.core.network.json.DefaultIfNullAdapter.Companion.DefaultIfNullAdapterFactory
|
||||
import app.pachli.core.network.json.GuardedAdapter.Companion.GuardedAdapterFactory
|
||||
import app.pachli.core.network.json.BooleanIfNull
|
||||
import app.pachli.core.network.json.DefaultIfNull
|
||||
import app.pachli.core.network.json.Guarded
|
||||
import app.pachli.core.network.model.Status
|
||||
import app.pachli.core.network.model.TimelineAccount
|
||||
import app.pachli.viewdata.StatusViewData
|
||||
|
@ -101,8 +102,9 @@ fun mockStatusEntityWithAccount(
|
|||
val mockedStatus = mockStatus(id)
|
||||
val moshi = Moshi.Builder()
|
||||
.add(Date::class.java, Rfc3339DateJsonAdapter())
|
||||
.add(GuardedAdapterFactory())
|
||||
.add(DefaultIfNullAdapterFactory())
|
||||
.add(Guarded.Factory())
|
||||
.add(DefaultIfNull.Factory())
|
||||
.add(BooleanIfNull.Factory())
|
||||
.build()
|
||||
|
||||
return TimelineStatusWithAccount(
|
||||
|
|
|
@ -19,7 +19,7 @@ package app.pachli.di
|
|||
|
||||
import app.pachli.components.compose.MediaUploader
|
||||
import app.pachli.core.network.di.NetworkModule
|
||||
import app.pachli.core.network.json.GuardedAdapter
|
||||
import app.pachli.core.network.json.Guarded
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.adapters.Rfc3339DateJsonAdapter
|
||||
import dagger.Module
|
||||
|
@ -41,7 +41,7 @@ object FakeNetworkModule {
|
|||
@Singleton
|
||||
fun providesMoshi(): Moshi = Moshi.Builder()
|
||||
.add(Date::class.java, Rfc3339DateJsonAdapter())
|
||||
.add(GuardedAdapter.Companion.GuardedAdapterFactory())
|
||||
.add(Guarded.Factory())
|
||||
.build()
|
||||
|
||||
@Provides
|
||||
|
|
|
@ -22,8 +22,9 @@ import android.os.Build
|
|||
import app.pachli.core.common.util.versionName
|
||||
import app.pachli.core.mastodon.model.MediaUploadApi
|
||||
import app.pachli.core.network.BuildConfig
|
||||
import app.pachli.core.network.json.DefaultIfNullAdapter.Companion.DefaultIfNullAdapterFactory
|
||||
import app.pachli.core.network.json.GuardedAdapter.Companion.GuardedAdapterFactory
|
||||
import app.pachli.core.network.json.BooleanIfNull
|
||||
import app.pachli.core.network.json.DefaultIfNull
|
||||
import app.pachli.core.network.json.Guarded
|
||||
import app.pachli.core.network.retrofit.InstanceSwitchAuthInterceptor
|
||||
import app.pachli.core.network.retrofit.MastodonApi
|
||||
import app.pachli.core.preferences.PrefKeys.HTTP_PROXY_ENABLED
|
||||
|
@ -63,8 +64,9 @@ object NetworkModule {
|
|||
@Singleton
|
||||
fun providesMoshi(): Moshi = Moshi.Builder()
|
||||
.add(Date::class.java, Rfc3339DateJsonAdapter())
|
||||
.add(GuardedAdapterFactory())
|
||||
.add(DefaultIfNullAdapterFactory())
|
||||
.add(Guarded.Factory())
|
||||
.add(DefaultIfNull.Factory())
|
||||
.add(BooleanIfNull.Factory())
|
||||
.build()
|
||||
|
||||
@Provides
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright 2024 Pachli Association
|
||||
*
|
||||
* This file is a part of Pachli.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||
* see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
package app.pachli.core.network.json
|
||||
|
||||
import com.squareup.moshi.JsonAdapter
|
||||
import com.squareup.moshi.JsonQualifier
|
||||
import com.squareup.moshi.JsonReader
|
||||
import com.squareup.moshi.JsonWriter
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import java.lang.reflect.Type
|
||||
|
||||
/**
|
||||
* A [JsonQualifier] for use with [Boolean] properties to indicate that their
|
||||
* value be set to the given [value] if the JSON property is `null`.
|
||||
*
|
||||
* Absent properties use the property's default value as normal.
|
||||
*
|
||||
* Usage:
|
||||
* ```
|
||||
* val moshi = Moshi.Builder()
|
||||
* .add(BooleanIfNull.Factory())
|
||||
* .build()
|
||||
*
|
||||
* @JsonClass(generateAdapter = true)
|
||||
* data class Foo(
|
||||
* @BooleanIfNull(false) val data: Boolean
|
||||
* )
|
||||
* ```
|
||||
*/
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@JsonQualifier
|
||||
annotation class BooleanIfNull(val value: Boolean) {
|
||||
class Factory : JsonAdapter.Factory {
|
||||
override fun create(
|
||||
type: Type,
|
||||
annotations: MutableSet<out Annotation>,
|
||||
moshi: Moshi,
|
||||
): JsonAdapter<*>? {
|
||||
val delegateAnnotations = Types.nextAnnotations(
|
||||
annotations,
|
||||
BooleanIfNull::class.java,
|
||||
) ?: return null
|
||||
val delegate = moshi.nextAdapter<Any>(
|
||||
this,
|
||||
type,
|
||||
delegateAnnotations,
|
||||
)
|
||||
|
||||
val annotation = annotations.first { it is BooleanIfNull } as BooleanIfNull
|
||||
return Adapter(delegate, annotation.value)
|
||||
}
|
||||
|
||||
private class Adapter(private val delegate: JsonAdapter<Any>, val default: Boolean) : JsonAdapter<Any>() {
|
||||
override fun fromJson(reader: JsonReader): Any {
|
||||
val value = reader.readJsonValue()
|
||||
return value as? Boolean ?: default
|
||||
}
|
||||
|
||||
override fun toJson(writer: JsonWriter, value: Any?) = delegate.toJson(writer, value)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright 2024 Pachli Association
|
||||
*
|
||||
* This file is a part of Pachli.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||
* see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
package app.pachli.core.network.json
|
||||
|
||||
import com.squareup.moshi.JsonAdapter
|
||||
import com.squareup.moshi.JsonQualifier
|
||||
import com.squareup.moshi.JsonReader
|
||||
import com.squareup.moshi.JsonWriter
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import java.lang.reflect.Type
|
||||
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@JsonQualifier
|
||||
annotation class DefaultIfNull {
|
||||
class Factory : JsonAdapter.Factory {
|
||||
override fun create(
|
||||
type: Type,
|
||||
annotations: MutableSet<out Annotation>,
|
||||
moshi: Moshi,
|
||||
): JsonAdapter<*>? {
|
||||
val delegateAnnotations = Types.nextAnnotations(
|
||||
annotations,
|
||||
DefaultIfNull::class.java,
|
||||
) ?: return null
|
||||
val delegate = moshi.nextAdapter<Any>(
|
||||
this,
|
||||
type,
|
||||
delegateAnnotations,
|
||||
)
|
||||
return DefaultIfNullAdapter(delegate)
|
||||
}
|
||||
|
||||
private class DefaultIfNullAdapter(private val delegate: JsonAdapter<Any>) : JsonAdapter<Any>() {
|
||||
override fun fromJson(reader: JsonReader): Any? {
|
||||
val value = reader.readJsonValue()
|
||||
if (value is Map<*, *>) {
|
||||
val withoutNulls = value.filterValues { it != null }
|
||||
return delegate.fromJsonValue(withoutNulls)
|
||||
}
|
||||
return delegate.fromJsonValue(value)
|
||||
}
|
||||
|
||||
override fun toJson(writer: JsonWriter, value: Any?) {
|
||||
return delegate.toJson(writer, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Copyright 2024 Pachli Association
|
||||
*
|
||||
* This file is a part of Pachli.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||
* see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
package app.pachli.core.network.json
|
||||
|
||||
import com.squareup.moshi.JsonAdapter
|
||||
import com.squareup.moshi.JsonQualifier
|
||||
import com.squareup.moshi.JsonReader
|
||||
import com.squareup.moshi.JsonWriter
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import java.lang.reflect.Type
|
||||
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@JsonQualifier
|
||||
annotation class DefaultIfNull
|
||||
|
||||
class DefaultIfNullAdapter(private val delegate: JsonAdapter<Any>) : JsonAdapter<Any>() {
|
||||
override fun fromJson(reader: JsonReader): Any? {
|
||||
val value = reader.readJsonValue()
|
||||
if (value is Map<*, *>) {
|
||||
val withoutNulls = value.filterValues { it != null }
|
||||
return delegate.fromJsonValue(withoutNulls)
|
||||
}
|
||||
return delegate.fromJsonValue(value)
|
||||
}
|
||||
|
||||
override fun toJson(writer: JsonWriter, value: Any?) {
|
||||
return delegate.toJson(writer, value)
|
||||
}
|
||||
|
||||
companion object {
|
||||
class DefaultIfNullAdapterFactory : Factory {
|
||||
override fun create(
|
||||
type: Type,
|
||||
annotations: MutableSet<out Annotation>,
|
||||
moshi: Moshi,
|
||||
): JsonAdapter<*>? {
|
||||
val delegateAnnotations = Types.nextAnnotations(
|
||||
annotations,
|
||||
DefaultIfNull::class.java,
|
||||
) ?: return null
|
||||
val delegate = moshi.nextAdapter<Any>(
|
||||
this,
|
||||
type,
|
||||
delegateAnnotations,
|
||||
)
|
||||
return DefaultIfNullAdapter(delegate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2024 Pachli Association
|
||||
*
|
||||
* This file is a part of Pachli.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||
* see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
package app.pachli.core.network.json
|
||||
|
||||
import com.squareup.moshi.JsonAdapter
|
||||
import com.squareup.moshi.JsonDataException
|
||||
import com.squareup.moshi.JsonQualifier
|
||||
import com.squareup.moshi.JsonReader
|
||||
import com.squareup.moshi.JsonWriter
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import java.lang.reflect.Type
|
||||
|
||||
/**
|
||||
* Deserialize this field as the given type, or null if the field value is not
|
||||
* this type.
|
||||
*/
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@JsonQualifier
|
||||
annotation class Guarded {
|
||||
class Factory : JsonAdapter.Factory {
|
||||
override fun create(
|
||||
type: Type,
|
||||
annotations: MutableSet<out Annotation>,
|
||||
moshi: Moshi,
|
||||
): JsonAdapter<*>? {
|
||||
val delegateAnnotations = Types.nextAnnotations(
|
||||
annotations,
|
||||
Guarded::class.java,
|
||||
) ?: return null
|
||||
val delegate = moshi.nextAdapter<Any>(
|
||||
this,
|
||||
type,
|
||||
delegateAnnotations,
|
||||
)
|
||||
return GuardedAdapter(delegate)
|
||||
}
|
||||
|
||||
private class GuardedAdapter(private val delegate: JsonAdapter<*>) : JsonAdapter<Any>() {
|
||||
override fun fromJson(reader: JsonReader): Any? {
|
||||
val peeked = reader.peekJson()
|
||||
val result = try {
|
||||
delegate.fromJson(peeked)
|
||||
} catch (_: JsonDataException) {
|
||||
null
|
||||
} finally {
|
||||
peeked.close()
|
||||
}
|
||||
reader.skipValue()
|
||||
return result
|
||||
}
|
||||
|
||||
override fun toJson(writer: JsonWriter, value: Any?) {
|
||||
throw UnsupportedOperationException("@Guarded is only used to desererialize objects")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
* Copyright 2024 Pachli Association
|
||||
*
|
||||
* This file is a part of Pachli.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||
* see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
package app.pachli.core.network.json
|
||||
|
||||
import com.squareup.moshi.JsonAdapter
|
||||
import com.squareup.moshi.JsonDataException
|
||||
import com.squareup.moshi.JsonQualifier
|
||||
import com.squareup.moshi.JsonReader
|
||||
import com.squareup.moshi.JsonWriter
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import java.lang.reflect.Type
|
||||
|
||||
/**
|
||||
* Deserialize this field as the given type, or null if the field value is not
|
||||
* this type.
|
||||
*/
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@JsonQualifier
|
||||
annotation class Guarded
|
||||
|
||||
/**
|
||||
* Parse the given field as either the delegate type, or null if it does not parse
|
||||
* as that type.
|
||||
*/
|
||||
class GuardedAdapter(private val delegate: JsonAdapter<*>) : JsonAdapter<Any>() {
|
||||
override fun fromJson(reader: JsonReader): Any? {
|
||||
val peeked = reader.peekJson()
|
||||
val result = try {
|
||||
delegate.fromJson(peeked)
|
||||
} catch (_: JsonDataException) {
|
||||
null
|
||||
} finally {
|
||||
peeked.close()
|
||||
}
|
||||
reader.skipValue()
|
||||
return result
|
||||
}
|
||||
|
||||
override fun toJson(writer: JsonWriter, value: Any?) {
|
||||
throw UnsupportedOperationException("@Guarded is only used to desererialize objects")
|
||||
}
|
||||
|
||||
companion object {
|
||||
class GuardedAdapterFactory : Factory {
|
||||
override fun create(
|
||||
type: Type,
|
||||
annotations: MutableSet<out Annotation>,
|
||||
moshi: Moshi,
|
||||
): JsonAdapter<*>? {
|
||||
val delegateAnnotations = Types.nextAnnotations(
|
||||
annotations,
|
||||
Guarded::class.java,
|
||||
) ?: return null
|
||||
val delegate = moshi.nextAdapter<Any>(
|
||||
this,
|
||||
type,
|
||||
delegateAnnotations,
|
||||
)
|
||||
return GuardedAdapter(delegate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package app.pachli.core.network.model
|
||||
|
||||
import app.pachli.core.network.json.BooleanIfNull
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import java.util.Date
|
||||
|
@ -11,10 +12,11 @@ data class Poll(
|
|||
val expired: Boolean,
|
||||
val multiple: Boolean,
|
||||
@Json(name = "votes_count") val votesCount: Int,
|
||||
// nullable for compatibility with Pleroma
|
||||
@Json(name = "voters_count") val votersCount: Int?,
|
||||
val options: List<PollOption>,
|
||||
val voted: Boolean,
|
||||
// Friendica can incorrectly return null for `voted`. Default to false.
|
||||
// https://github.com/friendica/friendica/issues/13922
|
||||
@BooleanIfNull(false) val voted: Boolean,
|
||||
@Json(name = "own_votes") val ownVotes: List<Int>?,
|
||||
) {
|
||||
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
package app.pachli.core.network.json
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.squareup.moshi.JsonClass
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.adapter
|
||||
import org.junit.Test
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
class BooleanIfNullTest {
|
||||
private val moshi = Moshi.Builder()
|
||||
.add(BooleanIfNull.Factory())
|
||||
.build()
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Data(@BooleanIfNull(false) val x: Boolean)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Data2(@BooleanIfNull(true) val x: Boolean)
|
||||
|
||||
@Test
|
||||
fun `true x is true`() {
|
||||
val jsonInput = """
|
||||
{
|
||||
"x": true
|
||||
}
|
||||
""".trimIndent()
|
||||
assertThat(moshi.adapter<Data>().fromJson(jsonInput)).isEqualTo(Data(x = true))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `false x is false`() {
|
||||
val jsonInput = """
|
||||
{
|
||||
"x": false
|
||||
}
|
||||
""".trimIndent()
|
||||
assertThat(moshi.adapter<Data>().fromJson(jsonInput)).isEqualTo(Data(x = false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `null x is false`() {
|
||||
val jsonInput = """
|
||||
{
|
||||
"x": null
|
||||
}
|
||||
""".trimIndent()
|
||||
assertThat(moshi.adapter<Data>().fromJson(jsonInput)).isEqualTo(Data(x = false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `null x is true`() {
|
||||
val jsonInput = """
|
||||
{
|
||||
"x": null
|
||||
}
|
||||
""".trimIndent()
|
||||
assertThat(moshi.adapter<Data2>().fromJson(jsonInput)).isEqualTo(Data2(x = true))
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
package app.pachli.core.network.json
|
||||
|
||||
import app.pachli.core.network.json.DefaultIfNullAdapter.Companion.DefaultIfNullAdapterFactory
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.squareup.moshi.JsonClass
|
||||
import com.squareup.moshi.Moshi
|
||||
|
@ -11,7 +10,7 @@ import org.junit.Test
|
|||
class DefaultIfNullTest {
|
||||
|
||||
private val moshi = Moshi.Builder()
|
||||
.add(DefaultIfNullAdapterFactory())
|
||||
.add(DefaultIfNull.Factory())
|
||||
.build()
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package app.pachli.core.network.json
|
||||
|
||||
import app.pachli.core.network.json.GuardedAdapter.Companion.GuardedAdapterFactory
|
||||
import app.pachli.core.network.model.Relationship
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.squareup.moshi.Moshi
|
||||
|
@ -11,7 +10,7 @@ import org.junit.Test
|
|||
class GuardedAdapterTest {
|
||||
|
||||
private val moshi = Moshi.Builder()
|
||||
.add(GuardedAdapterFactory())
|
||||
.add(Guarded.Factory())
|
||||
.build()
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue