Skip to content

Commit

Permalink
Suspend every & verify
Browse files Browse the repository at this point in the history
  • Loading branch information
SalomonBrys committed Feb 4, 2022
1 parent 49494f3 commit c03f11b
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 6 deletions.
22 changes: 22 additions & 0 deletions mockmp-coroutines/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
plugins {
id("org.kodein.library.mpp")
}

val coroutinesVersion: String by rootProject.extra

kodein {
kotlin {
common.main.dependencies {
api(project(":mockmp-runtime"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion")
}
add(kodeinTargets.jvm.jvm)
add(kodeinTargets.native.all)
add(kodeinTargets.js.js)
}
}

kodeinUpload {
name = "mockmp-coroutines"
description = "MocKMP for coroutines"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.kodein.mock.coroutines

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.test.TestScope
import org.kodein.mock.ArgConstraintsBuilder
import org.kodein.mock.Mocker


public suspend fun <T> Mocker.every(block: suspend ArgConstraintsBuilder.() -> T): Mocker.Every<T> {

}
21 changes: 17 additions & 4 deletions mockmp-runtime/src/commonMain/kotlin/org/kodein/mock/Mocker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@ public class Mocker {
}
}

public fun <T> every(block: ArgConstraintsBuilder.() -> T) : Every<T> {
// This will be inlined twice: once for regular functions, and once for suspend functions.
private inline fun <T> everyImpl(block: ArgConstraintsBuilder.() -> T): Every<T> {
if (specialMode != null) error("Cannot be inside a definition block AND a verification block")
val mode = SpecialMode.DEFINITION
specialMode = mode
specialMode = SpecialMode.DEFINITION
val builder = ArgConstraintsBuilder()
try {
builder.block()
Expand All @@ -126,10 +126,17 @@ public class Mocker {
}
}

public fun <T> every(block: ArgConstraintsBuilder.() -> T) : Every<T> =
everyImpl { block() }

public suspend fun <T> everySuspend(block: suspend ArgConstraintsBuilder.() -> T): Every<T> =
everyImpl { block() }

@Deprecated("Renamed every", ReplaceWith("every(block)"), level = DeprecationLevel.ERROR)
public fun <T> on(block: ArgConstraintsBuilder.() -> T) : Every<T> = every(block)

public fun verify(exhaustive: Boolean = true, inOrder: Boolean = true, block: ArgConstraintsBuilder.() -> Unit) {
// This will be inlined twice: once for regular functions, and once for suspend functions.
private inline fun verifyImpl(exhaustive: Boolean, inOrder: Boolean, block: ArgConstraintsBuilder.() -> Unit) {
if (specialMode != null) error("Cannot be inside a definition block AND a verification block")
val mode = SpecialMode.VERIFICATION(exhaustive, inOrder)
specialMode = mode
Expand All @@ -145,4 +152,10 @@ public class Mocker {
specialMode = null
}
}

public fun verify(exhaustive: Boolean = true, inOrder: Boolean = true, block: ArgConstraintsBuilder.() -> Unit): Unit =
verifyImpl(exhaustive, inOrder) { block() }

public suspend fun verifySuspend(exhaustive: Boolean = true, inOrder: Boolean = true, block: suspend ArgConstraintsBuilder.() -> Unit): Unit =
verifyImpl(exhaustive, inOrder) { block() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ public abstract class TestsWithMocks {

protected abstract fun setUpMocks()

protected fun <T> every(block: ArgConstraintsBuilder.() -> T) : Mocker.Every<T> = mocker.every(block)
public fun verify(exhaustive: Boolean = true, inOrder: Boolean = true, block: ArgConstraintsBuilder.() -> Unit): Unit = mocker.verify(exhaustive = exhaustive, inOrder = inOrder, block)
protected fun <T> every(block: ArgConstraintsBuilder.() -> T) : Mocker.Every<T> =
mocker.every(block)
protected suspend fun <T> everySuspend(block: suspend ArgConstraintsBuilder.() -> T) : Mocker.Every<T> =
mocker.everySuspend(block)

public fun verify(exhaustive: Boolean = true, inOrder: Boolean = true, block: ArgConstraintsBuilder.() -> Unit): Unit =
mocker.verify(exhaustive = exhaustive, inOrder = inOrder, block)
public suspend fun verifySuspend(exhaustive: Boolean = true, inOrder: Boolean = true, block: suspend ArgConstraintsBuilder.() -> Unit): Unit =
mocker.verifySuspend(exhaustive = exhaustive, inOrder = inOrder, block)
}
1 change: 1 addition & 0 deletions tests/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ kodein {
implementation(kotlin("test"))
implementation(project(":mockmp-runtime"))
implementation(project(":mockmp-test-helper"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0")
}
// Adding KSP JVM result to COMMON source set
kotlin.srcDir("build/generated/ksp/jvmTest/kotlin")
Expand Down
24 changes: 24 additions & 0 deletions tests/src/commonTest/kotlin/tests/VerificationTests.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package tests

import data.fakeData
import foo.Bar
import foo.Foo
import foo.MockBar
import foo.MockFoo
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.kodein.mock.Mocker
import org.kodein.mock.UsesMocks
import kotlin.test.BeforeTest
Expand Down Expand Up @@ -166,4 +170,24 @@ class VerificationTests {
}
assertEquals("Argument 1: Expected <42>, actual <21>", ex.message)
}

@Test
@ExperimentalCoroutinesApi
fun testSuspend() = runTest {
val bar = MockBar(mocker)
mocker.everySuspend { bar.newData() } returns fakeData()
val data = bar.newData()
assertEquals(fakeData(), data)
mocker.verifySuspend { bar.newData() }
}

@Test
@ExperimentalCoroutinesApi
fun testSuspendFails() = runTest {
val bar = MockBar(mocker)
val ex = assertFailsWith<AssertionError> {
mocker.verifySuspend { bar.newData() }
}
assertEquals("Expected a call to MockBar.newData() but call list was empty", ex.message)
}
}

0 comments on commit c03f11b

Please sign in to comment.