Add test case for applying locus id in notification builder

This commit is contained in:
Adam Brown 2023-01-17 21:36:23 +00:00
parent 9cd9520e52
commit 69c55c05dc
6 changed files with 46 additions and 7 deletions

View File

@ -20,7 +20,7 @@ class ExpectTest(override val coroutineContext: CoroutineContext) : ExpectTestSc
override fun verifyExpects() { override fun verifyExpects() {
expects.forEach { (times, block) -> coVerify(exactly = times) { block.invoke(this) } } expects.forEach { (times, block) -> coVerify(exactly = times) { block.invoke(this) } }
groups.forEach { coVerifyOrder { it.invoke(this) } } groups.forEach { coVerifyAll { it.invoke(this) } }
} }
override fun <T> T.expectUnit(times: Int, block: suspend MockKMatcherScope.(T) -> Unit) { override fun <T> T.expectUnit(times: Int, block: suspend MockKMatcherScope.(T) -> Unit) {

View File

@ -16,6 +16,11 @@ fun DeviceMeta.onAtLeastO(block: () -> Unit) {
whenXOrHigher(Build.VERSION_CODES.O, block, fallback = {}) whenXOrHigher(Build.VERSION_CODES.O, block, fallback = {})
} }
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.Q, lambda = 0)
fun DeviceMeta.onAtLeastQ(block: () -> Unit) {
whenXOrHigher(Build.VERSION_CODES.Q, block, fallback = {})
}
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.R, lambda = 0) @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.R, lambda = 0)
fun DeviceMeta.onAtLeastR(block: () -> Unit) { fun DeviceMeta.onAtLeastR(block: () -> Unit) {
whenXOrHigher(Build.VERSION_CODES.R, block, fallback = {}) whenXOrHigher(Build.VERSION_CODES.R, block, fallback = {})

View File

@ -1,8 +1,12 @@
package fake package fake
import android.app.Notification import android.app.Notification
import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import test.delegateReturn
class FakeNotificationBuilder { class FakeNotificationBuilder {
val instance = mockk<Notification.Builder>(relaxed = true) val instance = mockk<Notification.Builder>(relaxed = true)
fun givenBuilds() = every { instance.build() }.delegateReturn()
} }

View File

@ -9,9 +9,9 @@ import android.graphics.drawable.Icon
import app.dapk.st.core.DeviceMeta import app.dapk.st.core.DeviceMeta
import app.dapk.st.core.isAtLeastO import app.dapk.st.core.isAtLeastO
import app.dapk.st.core.onAtLeastO import app.dapk.st.core.onAtLeastO
import app.dapk.st.core.onAtLeastQ
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Suppress("ObjectPropertyName")
private val _builderFactory: (Context, String, DeviceMeta) -> Notification.Builder = { context, channel, deviceMeta -> private val _builderFactory: (Context, String, DeviceMeta) -> Notification.Builder = { context, channel, deviceMeta ->
deviceMeta.isAtLeastO( deviceMeta.isAtLeastO(
block = { Notification.Builder(context, channel) }, block = { Notification.Builder(context, channel) },
@ -23,7 +23,8 @@ class AndroidNotificationBuilder(
private val context: Context, private val context: Context,
private val deviceMeta: DeviceMeta, private val deviceMeta: DeviceMeta,
private val notificationStyleBuilder: AndroidNotificationStyleBuilder, private val notificationStyleBuilder: AndroidNotificationStyleBuilder,
private val builderFactory: (Context, String, DeviceMeta) -> Notification.Builder = _builderFactory private val builderFactory: (Context, String, DeviceMeta) -> Notification.Builder = _builderFactory,
private val notificationExtensions: NotificationExtensions = DefaultNotificationExtensions(deviceMeta),
) { ) {
@SuppressLint("NewApi") @SuppressLint("NewApi")
fun build(notification: AndroidNotification): Notification { fun build(notification: AndroidNotification): Notification {
@ -42,7 +43,7 @@ class AndroidNotificationBuilder(
} }
.ifNotNull(notification.category) { setCategory(it) } .ifNotNull(notification.category) { setCategory(it) }
.ifNotNull(notification.shortcutId) { .ifNotNull(notification.shortcutId) {
setLocusId(LocusId(it)) with(notificationExtensions) { applyLocusId(it) }
deviceMeta.onAtLeastO { setShortcutId(it) } deviceMeta.onAtLeastO { setShortcutId(it) }
} }
.ifNotNull(notification.smallIcon) { setSmallIcon(it) } .ifNotNull(notification.smallIcon) { setSmallIcon(it) }

View File

@ -0,0 +1,16 @@
package app.dapk.st.notifications
import android.app.Notification
import android.content.LocusId
import app.dapk.st.core.DeviceMeta
import app.dapk.st.core.onAtLeastQ
interface NotificationExtensions {
fun Notification.Builder.applyLocusId(id: String)
}
internal class DefaultNotificationExtensions(private val deviceMeta: DeviceMeta) : NotificationExtensions {
override fun Notification.Builder.applyLocusId(id: String) {
deviceMeta.onAtLeastQ { setLocusId(LocusId(id)) }
}
}

View File

@ -1,12 +1,14 @@
package app.dapk.st.notifications package app.dapk.st.notifications
import android.app.Notification
import app.dapk.st.core.DeviceMeta import app.dapk.st.core.DeviceMeta
import fixture.NotificationDelegateFixtures.anAndroidNotification
import fake.FakeContext import fake.FakeContext
import fake.FakeNotificationBuilder import fake.FakeNotificationBuilder
import fake.aFakeMessagingStyle import fake.aFakeMessagingStyle
import fixture.NotificationDelegateFixtures.anAndroidNotification
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import org.amshove.kluent.shouldBeEqualTo
import org.junit.Test import org.junit.Test
import test.delegateReturn import test.delegateReturn
import test.runExpectTest import test.runExpectTest
@ -15,21 +17,30 @@ private val A_MESSAGING_STYLE = aFakeMessagingStyle()
class AndroidNotificationBuilderTest { class AndroidNotificationBuilderTest {
private val aPlatformNotification = mockk<Notification>()
private val fakeContext = FakeContext() private val fakeContext = FakeContext()
private val fakeNotificationBuilder = FakeNotificationBuilder() private val fakeNotificationBuilder = FakeNotificationBuilder()
private val fakeAndroidNotificationStyleBuilder = FakeAndroidNotificationStyleBuilder() private val fakeAndroidNotificationStyleBuilder = FakeAndroidNotificationStyleBuilder()
private val fakeNotificationExtensions = FakeNotificationExtensions()
private val builder = AndroidNotificationBuilder( private val builder = AndroidNotificationBuilder(
fakeContext.instance, fakeContext.instance,
DeviceMeta(apiVersion = 26), DeviceMeta(apiVersion = 26),
fakeAndroidNotificationStyleBuilder.instance, fakeAndroidNotificationStyleBuilder.instance,
builderFactory = { _, _, _ -> fakeNotificationBuilder.instance }, builderFactory = { _, _, _ -> fakeNotificationBuilder.instance },
notificationExtensions = fakeNotificationExtensions
) )
@Test @Test
fun `applies all builder options`() = runExpectTest { fun `applies all builder options`() = runExpectTest {
val notification = anAndroidNotification() val notification = anAndroidNotification()
fakeAndroidNotificationStyleBuilder.given(notification.messageStyle!!).returns(A_MESSAGING_STYLE) fakeAndroidNotificationStyleBuilder.given(notification.messageStyle!!).returns(A_MESSAGING_STYLE)
fakeNotificationBuilder.givenBuilds().returns(aPlatformNotification)
with(fakeNotificationExtensions) {
fakeNotificationExtensions.expect { fakeNotificationBuilder.instance.applyLocusId(notification.shortcutId!!) }
}
fakeNotificationBuilder.instance.captureExpects { fakeNotificationBuilder.instance.captureExpects {
it.setOnlyAlertOnce(!notification.alertMoreThanOnce) it.setOnlyAlertOnce(!notification.alertMoreThanOnce)
it.setAutoCancel(notification.autoCancel) it.setAutoCancel(notification.autoCancel)
@ -45,9 +56,9 @@ class AndroidNotificationBuilderTest {
it.setLargeIcon(notification.largeIcon) it.setLargeIcon(notification.largeIcon)
it.build() it.build()
} }
val result = builder.build(notification)
val ignoredResult = builder.build(notification) result shouldBeEqualTo aPlatformNotification
verifyExpects() verifyExpects()
} }
} }
@ -57,3 +68,5 @@ class FakeAndroidNotificationStyleBuilder {
fun given(style: AndroidNotificationStyle) = every { instance.build(style) }.delegateReturn() fun given(style: AndroidNotificationStyle) = every { instance.build(style) }.delegateReturn()
} }
private class FakeNotificationExtensions : NotificationExtensions by mockk()