Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better error message in PersistState #720

Merged
merged 1 commit into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion mvrx/src/main/kotlin/com/airbnb/mvrx/PersistState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ private fun <T : Any?> Bundle.putAny(key: String?, value: T): Bundle {
is Parcelable -> putParcelable(key, value)
is Serializable -> putSerializable(key, value)
null -> putString(key, null)
else -> error("Cannot persist $key. It must be null, Serializable, or Parcelable.")
// The null case is covered above so can avoid the null check here.
else -> error("Cannot persist '$key': Class ${value!!::class.java.name} must be null, Serializable, or Parcelable.")
}
return this
}
Expand Down
85 changes: 65 additions & 20 deletions mvrx/src/test/kotlin/com/airbnb/mvrx/PersistedStateTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Assert.assertThrows
import org.junit.Test
import org.mockito.Mockito

Expand Down Expand Up @@ -44,12 +45,21 @@ class PersistedStateTest : BaseTest() {
assertEquals(5, newState.count)
}

@Test(expected = IllegalStateException::class)
@Test
fun validatesMissingKeyInBundle() {
data class State(@PersistState val count: Int = 5) : MavericksState
val exception: IllegalStateException = assertThrows(
IllegalStateException::class.java
) {
data class State(@PersistState val count: Int = 5) : MavericksState

val newState = restorePersistedMavericksState(Bundle(), State(), validation = true)
assertEquals(5, newState.count)
val newState = restorePersistedMavericksState(Bundle(), State(), validation = true)
assertEquals(5, newState.count)
}
assertEquals(
"savedInstanceState bundle should have a key for state property at position 0 but it was missing.",
// The mockito mock adds a random id string at the end.
exception.message?.substringBeforeLast("$")
)
}

@Test
Expand Down Expand Up @@ -188,11 +198,20 @@ class PersistedStateTest : BaseTest() {
assertEquals(3, state.data[0].count)
}

@Test(expected = IllegalStateException::class)
@Test()
fun testNonParcelableList() {
data class State2(@PersistState val data: List<Context> = listOf(Mockito.mock(Context::class.java))) : MavericksState
val exception: IllegalStateException = assertThrows(
IllegalStateException::class.java
) {
data class State2(@PersistState val data: List<Context> = listOf(Mockito.mock(Context::class.java))) : MavericksState

persistMavericksState(State2(), validation = true)
persistMavericksState(State2(), validation = true)
}
assertEquals(
"Cannot parcel android.content.Context\$MockitoMock",
// The mockito mock adds a random id string at the end.
exception.message?.substringBeforeLast("$")
)
}

@Test
Expand All @@ -204,11 +223,20 @@ class PersistedStateTest : BaseTest() {
assertEquals(3, state.data.take(1).first().count)
}

@Test(expected = IllegalStateException::class)
@Test()
fun testNonParcelableSet() {
data class State2(@PersistState val data: Set<Context> = setOf(Mockito.mock(Context::class.java))) : MavericksState
val exception: IllegalStateException = assertThrows(
IllegalStateException::class.java
) {
data class State2(@PersistState val data: Set<Context> = setOf(Mockito.mock(Context::class.java))) : MavericksState

persistMavericksState(State2(), validation = true)
persistMavericksState(State2(), validation = true)
}
assertEquals(
"Cannot parcel android.content.Context\$MockitoMock",
// The mockito mock adds a random id string at the end.
exception.message?.substringBeforeLast("$")
)
}

@Test
Expand All @@ -222,20 +250,37 @@ class PersistedStateTest : BaseTest() {
assertEquals(3, state.data["foo"]?.count)
}

@Test(expected = IllegalStateException::class)
@Test()
fun testNonParcelableMap() {
data class State2(
@PersistState val data: Map<String, Context> = mapOf("foo" to Mockito.mock(Context::class.java))
) : MavericksState

persistMavericksState(State2(), validation = true)
val exception: IllegalStateException = assertThrows(
IllegalStateException::class.java
) {
data class State2(
@PersistState val data: Map<String, Context> = mapOf("foo" to Mockito.mock(Context::class.java))
) : MavericksState

persistMavericksState(State2(), validation = true)
}
assertEquals(
"Cannot parcel android.content.Context\$MockitoMock",
// The mockito mock adds a random id string at the end.
exception.message?.substringBeforeLast("$")
)
}

@Test(expected = IllegalStateException::class)
@Test()
fun failOnNonParcelable() {
class NonParcelableClass
data class State(@PersistState val data: NonParcelableClass = NonParcelableClass()) : MavericksState
persistMavericksState(State())
val exception: IllegalStateException = assertThrows(
IllegalStateException::class.java
) {
class NonParcelableClass
data class State(@PersistState val data: NonParcelableClass = NonParcelableClass()) : MavericksState
persistMavericksState(State())
}
assertEquals(
"Cannot persist '0': Class com.airbnb.mvrx.PersistedStateTest\$failOnNonParcelable\$exception\$1\$NonParcelableClass must be null, Serializable, or Parcelable.",
exception.message
)
}

@Test
Expand Down
Loading