Skip to content

Commit

Permalink
Use type converter that cannot return null for date to avoid crash (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mchowning authored Nov 30, 2023
1 parent 38159f9 commit 0df5efe
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* Bug Fixes:
* Ensure we have the most up-to-date episode urls before attempting playback
([#1561](https://github.com/Automattic/pocket-casts-android/pull/1561))
* Prevent crash if database is missing date episode is published
([#1573](https://github.com/Automattic/pocket-casts-android/pull/1573))

7.52
-----
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package au.com.shiftyjelly.pocketcasts.models.converter

import androidx.room.TypeConverter
import io.sentry.Sentry
import timber.log.Timber
import java.time.Instant
import java.util.Date

class DateTypeConverter {
Expand All @@ -15,3 +18,29 @@ class DateTypeConverter {
return value?.time
}
}

typealias SafeDate = Date

// Type converter for dates that will not return null even if a null parameter is passed in.
class SafeDateTypeConverter {

@TypeConverter
fun toDate(value: Long?): SafeDate {
return if (value == null) {
"ShouldNotBeNullDateTypeConverter::toDate called with null parameter. Returning epoch date.".let {
Timber.w(it)
Sentry.addBreadcrumb(it)
}
EPOCH
} else {
Date(value)
}
}

@TypeConverter
fun toLong(value: SafeDate?): Long = value?.time ?: 0L

companion object {
private val EPOCH = Date(Instant.EPOCH.toEpochMilli())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import au.com.shiftyjelly.pocketcasts.models.converter.EpisodesSortTypeConverter
import au.com.shiftyjelly.pocketcasts.models.converter.PodcastAutoUpNextConverter
import au.com.shiftyjelly.pocketcasts.models.converter.PodcastLicensingEnumConverter
import au.com.shiftyjelly.pocketcasts.models.converter.PodcastsSortTypeConverter
import au.com.shiftyjelly.pocketcasts.models.converter.SafeDateTypeConverter
import au.com.shiftyjelly.pocketcasts.models.converter.SyncStatusConverter
import au.com.shiftyjelly.pocketcasts.models.converter.TrimModeTypeConverter
import au.com.shiftyjelly.pocketcasts.models.converter.UserEpisodeServerStatusConverter
Expand Down Expand Up @@ -69,6 +70,7 @@ import au.com.shiftyjelly.pocketcasts.localization.R as LR
AnonymousBumpStat.CustomEventPropsTypeConverter::class,
BundlePaidTypeConverter::class,
DateTypeConverter::class,
SafeDateTypeConverter::class,
EpisodePlayingStatusConverter::class,
EpisodeStatusEnumConverter::class,
EpisodesSortTypeConverter::class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import androidx.room.Ignore
import androidx.room.Index
import androidx.room.PrimaryKey
import au.com.shiftyjelly.pocketcasts.localization.R
import au.com.shiftyjelly.pocketcasts.models.converter.SafeDate
import au.com.shiftyjelly.pocketcasts.models.type.EpisodePlayingStatus
import au.com.shiftyjelly.pocketcasts.models.type.EpisodeStatusEnum
import java.io.Serializable
Expand All @@ -23,7 +24,7 @@ import java.util.Date
data class PodcastEpisode(
@PrimaryKey(autoGenerate = false) @ColumnInfo(name = "uuid") override var uuid: String,
@ColumnInfo(name = "episode_description") override var episodeDescription: String = "",
@ColumnInfo(name = "published_date") override var publishedDate: Date,
@ColumnInfo(name = "published_date") override var publishedDate: SafeDate,
@ColumnInfo(name = "title") override var title: String = "",
@ColumnInfo(name = "size_in_bytes") override var sizeInBytes: Long = 0,
@ColumnInfo(name = "episode_status") override var episodeStatus: EpisodeStatusEnum = EpisodeStatusEnum.NOT_DOWNLOADED,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package au.com.shiftyjelly.pocketcasts.models

import au.com.shiftyjelly.pocketcasts.models.converter.SafeDateTypeConverter
import junit.framework.TestCase.assertEquals
import org.junit.Test
import java.time.Instant
import java.util.Date

class SafeDateTypeConverterTest {

@Test
fun `creates date from non-null long`() {
val l = 125542352L
val expected = Date(l)
val actual = SafeDateTypeConverter().toDate(l)
assertEquals(expected, actual)
}

@Test
fun `creates date from null long`() {
val expected = Date(Instant.EPOCH.toEpochMilli())
val actual = SafeDateTypeConverter().toDate(null)
assertEquals(expected, actual)
}

@Test
fun `creates long from non-null date`() {
val expected = 125542352L
val d = Date(expected)
val actual = SafeDateTypeConverter().toLong(d)
assertEquals(expected, actual)
}

@Test
fun `creates long from null date`() {
val actual = SafeDateTypeConverter().toLong(null)
assertEquals(0L, actual)
}
}

0 comments on commit 0df5efe

Please sign in to comment.