diff --git a/.github/labeler.yml b/.github/labeler.yml index 488d6a77..3cf3be0f 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -18,5 +18,8 @@ documentation: - readmeOSS.adoc # Library -test-utils: +kmock: - kmock-gradle/**/* + +examples: + - examples/**/* diff --git a/.github/labels.yml b/.github/labels.yml index 26b8ed56..bd8282ee 100644 --- a/.github/labels.yml +++ b/.github/labels.yml @@ -66,3 +66,7 @@ - name: kmock description: KMock color: 000080 + +- name: examples + description: Examples + color: 000080 diff --git a/examples/src/commonTest/kotlin/tech/antibytes/kmock/example/SampleControllerSpec.kt b/examples/src/commonTest/kotlin/tech/antibytes/kmock/example/SampleControllerSpec.kt index 37224078..66a86c4e 100644 --- a/examples/src/commonTest/kotlin/tech/antibytes/kmock/example/SampleControllerSpec.kt +++ b/examples/src/commonTest/kotlin/tech/antibytes/kmock/example/SampleControllerSpec.kt @@ -16,18 +16,19 @@ import tech.antibytes.kmock.KMockContract.Collector import tech.antibytes.kmock.PropertyMockery import tech.antibytes.kmock.SyncFunMockery import tech.antibytes.kmock.Verifier +import tech.antibytes.kmock.assertWasCalledStrictlyWith import tech.antibytes.kmock.example.ExampleContract.SampleDomainObject import tech.antibytes.kmock.example.ExampleContract.SampleLocalRepository import tech.antibytes.kmock.example.ExampleContract.SampleRemoteRepository import tech.antibytes.kmock.verify import tech.antibytes.kmock.verifyOrder import tech.antibytes.kmock.verifyStrictOrder +import tech.antibytes.kmock.wasCalledWithArguments +import tech.antibytes.kmock.wasCalledWithArgumentsStrict +import tech.antibytes.kmock.wasCalledWithoutArguments import tech.antibytes.kmock.wasGotten import tech.antibytes.kmock.wasSet import tech.antibytes.kmock.wasSetTo -import tech.antibytes.kmock.withArguments -import tech.antibytes.kmock.withSameArguments -import tech.antibytes.kmock.withoutArguments import tech.antibytes.util.test.coroutine.AsyncTestReturnValue import tech.antibytes.util.test.coroutine.defaultTestContext import tech.antibytes.util.test.coroutine.runBlockingTestWithTimeout @@ -80,22 +81,22 @@ class SampleControllerSpec { // Then actual mustBe domainObject - verify(exactly = 1) { remote.fetch.withSameArguments(url) } - verify(exactly = 1) { local.store.withSameArguments(id[1], number) } + verify(exactly = 1) { remote.fetch.wasCalledWithArgumentsStrict(url) } + verify(exactly = 1) { local.store.wasCalledWithArgumentsStrict(id[1], number) } verifier.verifyStrictOrder { - withSameArguments(remote.fetch, url) + wasCalledWithArgumentsStrict(remote.fetch, url) wasGotten(domainObject.propId) wasSet(domainObject.propId) wasGotten(domainObject.propId) wasGotten(domainObject.propValue) - withSameArguments(local.store, id[1], number) + wasCalledWithArgumentsStrict(local.store, id[1], number) } verifier.verifyOrder { - withArguments(remote.fetch, url) + wasCalledWithArguments(remote.fetch, url) wasSetTo(domainObject.propId, "42") - withArguments(local.store, id[1]) + wasCalledWithArguments(local.store, id[1]) } } } @@ -134,20 +135,20 @@ class SampleControllerSpec { delay(20) - verify(exactly = 1) { local.contains.withSameArguments(idOrg) } - verify(exactly = 1) { local.fetch.withSameArguments(id) } - verify(exactly = 1) { remote.find.withSameArguments(idOrg) } + local.contains.assertWasCalledStrictlyWith(1, idOrg) + local.fetch.assertWasCalledStrictlyWith(1, id) + remote.find.assertWasCalledStrictlyWith(1, idOrg) verifier.verifyStrictOrder { - withSameArguments(local.contains, idOrg) - withSameArguments(remote.find, idOrg) + wasCalledWithArgumentsStrict(local.contains, idOrg) + wasCalledWithArgumentsStrict(remote.find, idOrg) wasGotten(domainObject.propId) - withSameArguments(local.fetch, id) + wasCalledWithArgumentsStrict(local.fetch, id) wasSet(domainObject.propId) } verifier.verifyOrder { - withoutArguments(local.contains, "abc") + wasCalledWithoutArguments(local.contains, "abc") } } } diff --git a/kmock/src/commonMain/kotlin/tech/antibytes/kmock/ArgumentMatcher.kt b/kmock/src/commonMain/kotlin/tech/antibytes/kmock/ArgumentMatcher.kt index c0f9bec4..07d3e065 100644 --- a/kmock/src/commonMain/kotlin/tech/antibytes/kmock/ArgumentMatcher.kt +++ b/kmock/src/commonMain/kotlin/tech/antibytes/kmock/ArgumentMatcher.kt @@ -8,7 +8,7 @@ package tech.antibytes.kmock import tech.antibytes.kmock.KMockContract.GetOrSet -internal fun Array?.withArguments(vararg values: Any?): Boolean { +internal fun Array?.wasCalledWithArguments(vararg values: Any?): Boolean { return when { this == null -> values.isEmpty() values.isEmpty() -> true @@ -16,11 +16,11 @@ internal fun Array?.withArguments(vararg values: Any?): Boolean { } } -internal fun Array?.withSameArguments(vararg values: Any?): Boolean { +internal fun Array?.wasCalledWithArgumentsStrict(vararg values: Any?): Boolean { return this?.contentDeepEquals(values) ?: values.isEmpty() } -internal fun Array?.withoutArguments(vararg values: Any?): Boolean { +internal fun Array?.wasCalledWithoutArguments(vararg values: Any?): Boolean { return if (this == null) { values.isNotEmpty() } else { diff --git a/kmock/src/commonMain/kotlin/tech/antibytes/kmock/FunMockery.kt b/kmock/src/commonMain/kotlin/tech/antibytes/kmock/FunMockery.kt index 01c90b42..c59257b8 100644 --- a/kmock/src/commonMain/kotlin/tech/antibytes/kmock/FunMockery.kt +++ b/kmock/src/commonMain/kotlin/tech/antibytes/kmock/FunMockery.kt @@ -132,6 +132,11 @@ abstract class FunMockery>( override fun getArgumentsForCall(callIndex: Int): Array? = arguments.access { it[callIndex] } override fun clear() { - TODO("Not yet implemented") + _returnValue.set(null) + _returnValues.set(null) + _sideEffect.set(null) + _calls.set(0) + provider.set(PROVIDER.NO_PROVIDER) + arguments.access { it.clear() } } } diff --git a/kmock/src/commonMain/kotlin/tech/antibytes/kmock/MockeryAssertion.kt b/kmock/src/commonMain/kotlin/tech/antibytes/kmock/MockeryAssertion.kt new file mode 100644 index 00000000..21cdc5d7 --- /dev/null +++ b/kmock/src/commonMain/kotlin/tech/antibytes/kmock/MockeryAssertion.kt @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022 Matthias Geisler (bitPogo) / All rights reserved. + * + * Use of this source code is governed by Apache v2.0 + */ + +package tech.antibytes.kmock + +import tech.antibytes.kmock.KMockContract.FunMockery + +fun FunMockery<*, *>.assertWasCalled( + exactly: Int, +) { + verify(exactly = exactly) { + this.wasCalledWithArguments() + } +} + +fun FunMockery<*, *>.assertWasCalledWith( + exactly: Int, + vararg arguments: Any? +) { + verify(exactly = exactly) { + this.wasCalledWithArguments(*arguments) + } +} + +fun FunMockery<*, *>.assertWasCalledStrictlyWith( + exactly: Int, + vararg arguments: Any? +) { + verify(exactly = exactly) { + this.wasCalledWithArgumentsStrict(*arguments) + } +} + +fun FunMockery<*, *>.assertWasNotCalled() { + verify(exactly = 0) { + this.wasCalledWithArguments() + } +} + +fun FunMockery<*, *>.assertWasNotCalledWith(vararg illegal: Any?) { + verify(exactly = 0) { + this.wasCalledWithArguments(*illegal) + } +} + +/** + * Assertion call for a FunMockery + * Fails if a given argument is referenced in a call + * @param arguments variable amount of nullable Any typed argument + * @throws AssertionError if a call contains a at least one given argument. + */ +fun FunMockery<*, *>.assertWasCalledWithout( + vararg arguments: Any? +) { + verify(atMost = 100) { + this.wasCalledWithoutArguments(*arguments) + } +} + +fun KMockContract.PropMockery<*>.assertWasGotten(exactly: Int) { + verify(exactly = exactly) { this.wasGotten() } +} + +fun KMockContract.PropMockery<*>.assertWasSet(exactly: Int) { + verify(exactly = exactly) { this.wasSet() } +} + +fun KMockContract.PropMockery<*>.assertWasSetTo(exactly: Int, value: Any?) { + verify(exactly = exactly) { this.wasSetTo(value) } +} diff --git a/kmock/src/commonMain/kotlin/tech/antibytes/kmock/PropertyMockery.kt b/kmock/src/commonMain/kotlin/tech/antibytes/kmock/PropertyMockery.kt index f0c9bcf0..714e9eed 100644 --- a/kmock/src/commonMain/kotlin/tech/antibytes/kmock/PropertyMockery.kt +++ b/kmock/src/commonMain/kotlin/tech/antibytes/kmock/PropertyMockery.kt @@ -117,6 +117,11 @@ class PropertyMockery( override fun getArgumentsForCall(callIndex: Int): GetOrSet = arguments.access { it[callIndex] } override fun clear() { - TODO("Not yet implemented") + provider.set(null) + _get.set(null) + _getMany.set(null) + _set.set { /*Do Nothing on Default*/ } + _calls.set(0) + arguments.access { it.clear() } } } diff --git a/kmock/src/commonMain/kotlin/tech/antibytes/kmock/Verification.kt b/kmock/src/commonMain/kotlin/tech/antibytes/kmock/Verification.kt index 8a2f8f6f..e7707805 100644 --- a/kmock/src/commonMain/kotlin/tech/antibytes/kmock/Verification.kt +++ b/kmock/src/commonMain/kotlin/tech/antibytes/kmock/Verification.kt @@ -66,6 +66,17 @@ private infix fun VerificationHandle.mustBeAtMost(value: Int) { } } +/** + * Verification function for a given assertion. + * Note:
    + *
  • any boundary parameter will cause a failure in combination with wasCalledWithoutArguments if at least one argument matches.
  • + *
+ * @param exactly Int or null - the exact amount of calls. This parameter overrides atLeast and atMost. Use null to deactivate the criteria. + * @param atLeast Int - the minimum amount of calls. + * @param atMost Int or null - the maximum amount of calls. Use null to deactivate the criteria. + * @param action ArgumentMatcher - Primary criteria to select VerificationHandles. + * @throws AssertionError if it does not match the given criteria. + */ fun verify( exactly: Int? = null, atLeast: Int = 1, diff --git a/kmock/src/commonMain/kotlin/tech/antibytes/kmock/VerificationChainBuilder.kt b/kmock/src/commonMain/kotlin/tech/antibytes/kmock/VerificationChainBuilder.kt index c9596f04..cfd8581e 100644 --- a/kmock/src/commonMain/kotlin/tech/antibytes/kmock/VerificationChainBuilder.kt +++ b/kmock/src/commonMain/kotlin/tech/antibytes/kmock/VerificationChainBuilder.kt @@ -19,16 +19,16 @@ class VerificationChainBuilder : KMockContract.VerificationHandleContainer { override fun toList(): List = handles.toList() } -fun VerificationChainBuilder.withArguments(mockery: FunMockery<*, *>, vararg arguments: Any?) { - this.add(mockery.withArguments(*arguments)) +fun VerificationChainBuilder.wasCalledWithArguments(mockery: FunMockery<*, *>, vararg arguments: Any?) { + this.add(mockery.wasCalledWithArguments(*arguments)) } -fun VerificationChainBuilder.withSameArguments(mockery: FunMockery<*, *>, vararg arguments: Any?) { - this.add(mockery.withSameArguments(*arguments)) +fun VerificationChainBuilder.wasCalledWithArgumentsStrict(mockery: FunMockery<*, *>, vararg arguments: Any?) { + this.add(mockery.wasCalledWithArgumentsStrict(*arguments)) } -fun VerificationChainBuilder.withoutArguments(mockery: FunMockery<*, *>, vararg arguments: Any?) { - this.add(mockery.withoutArguments(*arguments)) +fun VerificationChainBuilder.wasCalledWithoutArguments(mockery: FunMockery<*, *>, vararg arguments: Any?) { + this.add(mockery.wasCalledWithoutArguments(*arguments)) } fun VerificationChainBuilder.wasGotten(mockery: KMockContract.PropMockery<*>) { diff --git a/kmock/src/commonMain/kotlin/tech/antibytes/kmock/VerificationHandleFactory.kt b/kmock/src/commonMain/kotlin/tech/antibytes/kmock/VerificationHandleFactory.kt index 112f2260..c9bc4203 100644 --- a/kmock/src/commonMain/kotlin/tech/antibytes/kmock/VerificationHandleFactory.kt +++ b/kmock/src/commonMain/kotlin/tech/antibytes/kmock/VerificationHandleFactory.kt @@ -26,17 +26,19 @@ private fun traverseMock( return VerificationHandle(mock.id, callIndices) } -fun FunMockery<*, *>.withArguments( +fun FunMockery<*, *>.wasCalledWithArguments( vararg values: Any? -): VerificationHandle = traverseMock(this) { withArguments(*values) } +): VerificationHandle = traverseMock(this) { + wasCalledWithArguments(*values) +} -fun FunMockery<*, *>.withSameArguments( +fun FunMockery<*, *>.wasCalledWithArgumentsStrict( vararg values: Any? -): VerificationHandle = traverseMock(this) { withSameArguments(*values) } +): VerificationHandle = traverseMock(this) { wasCalledWithArgumentsStrict(*values) } -fun FunMockery<*, *>.withoutArguments( +fun FunMockery<*, *>.wasCalledWithoutArguments( vararg values: Any? -): VerificationHandle = traverseMock(this) { withoutArguments(*values) } +): VerificationHandle = traverseMock(this) { wasCalledWithoutArguments(*values) } fun PropMockery<*>.wasGotten(): VerificationHandle = traverseMock(this) { wasGotten() } diff --git a/kmock/src/commonMain/kotlin/tech/antibytes/kmock/Verifier.kt b/kmock/src/commonMain/kotlin/tech/antibytes/kmock/Verifier.kt index f4016c55..6b1f5045 100644 --- a/kmock/src/commonMain/kotlin/tech/antibytes/kmock/Verifier.kt +++ b/kmock/src/commonMain/kotlin/tech/antibytes/kmock/Verifier.kt @@ -23,6 +23,6 @@ class Verifier : KMockContract.Verifier, KMockContract.Collector { } override fun clear() { - TODO("Not yet implemented") + _references.access { it.clear() } } } diff --git a/kmock/src/commonTest/kotlin/tech/antibytes/kmock/ArgumentMatcherSpec.kt b/kmock/src/commonTest/kotlin/tech/antibytes/kmock/ArgumentMatcherSpec.kt index f7e0c64d..91b91d9f 100644 --- a/kmock/src/commonTest/kotlin/tech/antibytes/kmock/ArgumentMatcherSpec.kt +++ b/kmock/src/commonTest/kotlin/tech/antibytes/kmock/ArgumentMatcherSpec.kt @@ -23,7 +23,7 @@ class ArgumentMatcherSpec { val array = fixture.listFixture().toTypedArray() // When - val actual = array.withArguments(fixture.fixture()) + val actual = array.wasCalledWithArguments(fixture.fixture()) // Then actual mustBe false @@ -36,7 +36,7 @@ class ArgumentMatcherSpec { val array = fixture.listFixture().toTypedArray() // When - val actual = array.withArguments(array.first()) + val actual = array.wasCalledWithArguments(array.first()) // Then actual mustBe true @@ -49,7 +49,7 @@ class ArgumentMatcherSpec { val array = fixture.listFixture().toTypedArray() // When - val actual = array.withArguments() + val actual = array.wasCalledWithArguments() // Then actual mustBe true @@ -62,7 +62,7 @@ class ArgumentMatcherSpec { val array = null // When - val actual = array.withArguments() + val actual = array.wasCalledWithArguments() // Then actual mustBe true @@ -75,7 +75,7 @@ class ArgumentMatcherSpec { val array = null // When - val actual = array.withArguments(fixture.listFixture(), fixture.listFixture()) + val actual = array.wasCalledWithArguments(fixture.listFixture(), fixture.listFixture()) // Then actual mustBe false @@ -88,7 +88,7 @@ class ArgumentMatcherSpec { val array = fixture.listFixture(size = 8).toTypedArray() // When - val actual = array.withArguments(array[0], array[1], array[2], fixture.fixture()) + val actual = array.wasCalledWithArguments(array[0], array[1], array[2], fixture.fixture()) // Then actual mustBe false @@ -101,7 +101,7 @@ class ArgumentMatcherSpec { val array = fixture.listFixture(size = 8).toTypedArray() // When - val actual = array.withArguments(array[0], array[1], array[2], array[3]) + val actual = array.wasCalledWithArguments(array[0], array[1], array[2], array[3]) // Then actual mustBe true @@ -114,7 +114,7 @@ class ArgumentMatcherSpec { val array = fixture.listFixture().toTypedArray() // When - val actual = array.withSameArguments(fixture.fixture()) + val actual = array.wasCalledWithArgumentsStrict(fixture.fixture()) // Then actual mustBe false @@ -127,7 +127,7 @@ class ArgumentMatcherSpec { val array = fixture.listFixture(size = 1).toTypedArray() // When - val actual = array.withSameArguments(array.first()) + val actual = array.wasCalledWithArgumentsStrict(array.first()) // Then actual mustBe true @@ -140,7 +140,7 @@ class ArgumentMatcherSpec { val array = fixture.listFixture(size = 1).toTypedArray() // When - val actual = array.withSameArguments() + val actual = array.wasCalledWithArgumentsStrict() // Then actual mustBe false @@ -153,7 +153,7 @@ class ArgumentMatcherSpec { val array = null // When - val actual = array.withSameArguments(fixture.fixture()) + val actual = array.wasCalledWithArgumentsStrict(fixture.fixture()) // Then actual mustBe false @@ -166,7 +166,7 @@ class ArgumentMatcherSpec { val array = null // When - val actual = array.withSameArguments() + val actual = array.wasCalledWithArgumentsStrict() // Then actual mustBe true @@ -179,7 +179,7 @@ class ArgumentMatcherSpec { val array = fixture.listFixture(size = 8).toTypedArray() // When - val actual = array.withSameArguments(array[0], array[1], array[2], array[3]) + val actual = array.wasCalledWithArgumentsStrict(array[0], array[1], array[2], array[3]) // Then actual mustBe false @@ -192,7 +192,7 @@ class ArgumentMatcherSpec { val array = fixture.listFixture(size = 8).toTypedArray() // When - val actual = array.withSameArguments(*array) + val actual = array.wasCalledWithArgumentsStrict(*array) // Then actual mustBe true @@ -205,7 +205,7 @@ class ArgumentMatcherSpec { val array = null // When - val actual = array.withoutArguments() + val actual = array.wasCalledWithoutArguments() // Then actual mustBe false @@ -218,7 +218,7 @@ class ArgumentMatcherSpec { val array = null // When - val actual = array.withoutArguments(fixture.listFixture().toTypedArray()) + val actual = array.wasCalledWithoutArguments(fixture.listFixture().toTypedArray()) // Then actual mustBe true @@ -231,7 +231,7 @@ class ArgumentMatcherSpec { val array = fixture.listFixture().toTypedArray() // When - val actual = array.withoutArguments(fixture.fixture()) + val actual = array.wasCalledWithoutArguments(fixture.fixture()) // Then actual mustBe true @@ -244,7 +244,7 @@ class ArgumentMatcherSpec { val array = fixture.listFixture().toTypedArray() // When - val actual = array.withoutArguments(array.first()) + val actual = array.wasCalledWithoutArguments(array.first()) // Then actual mustBe false @@ -257,7 +257,7 @@ class ArgumentMatcherSpec { val array = fixture.listFixture().toTypedArray() // When - val actual = array.withoutArguments() + val actual = array.wasCalledWithoutArguments() // Then actual mustBe true @@ -270,7 +270,7 @@ class ArgumentMatcherSpec { val array = fixture.listFixture().toTypedArray() // When - val actual = array.withoutArguments() + val actual = array.wasCalledWithoutArguments() // Then actual mustBe true @@ -284,7 +284,7 @@ class ArgumentMatcherSpec { // When val actual = - array.withoutArguments(fixture.fixture(), fixture.fixture(), fixture.fixture()) + array.wasCalledWithoutArguments(fixture.fixture(), fixture.fixture(), fixture.fixture()) // Then actual mustBe true @@ -297,7 +297,7 @@ class ArgumentMatcherSpec { val array = fixture.listFixture(size = 8).toTypedArray() // When - val actual = array.withoutArguments( + val actual = array.wasCalledWithoutArguments( array[0], fixture.fixture(), fixture.fixture(), diff --git a/kmock/src/commonTest/kotlin/tech/antibytes/kmock/AsyncFunMockerySpec.kt b/kmock/src/commonTest/kotlin/tech/antibytes/kmock/AsyncFunMockerySpec.kt index 8b297393..cdabf290 100644 --- a/kmock/src/commonTest/kotlin/tech/antibytes/kmock/AsyncFunMockerySpec.kt +++ b/kmock/src/commonTest/kotlin/tech/antibytes/kmock/AsyncFunMockerySpec.kt @@ -9,6 +9,8 @@ package tech.antibytes.kmock import co.touchlab.stately.concurrency.AtomicReference import tech.antibytes.kmock.KMockContract.Collector import tech.antibytes.util.test.MockError +import tech.antibytes.util.test.annotations.IgnoreJs +import tech.antibytes.util.test.annotations.JsOnly import tech.antibytes.util.test.coroutine.AsyncTestReturnValue import tech.antibytes.util.test.coroutine.TestScopeDispatcher import tech.antibytes.util.test.coroutine.asyncMultiBlock @@ -1383,4 +1385,94 @@ class AsyncFunMockerySpec { return asyncMultiBlock } + + @Test + @IgnoreJs + @JsName("fn48") + fun `Given clear is called it clears the mock`(): AsyncTestReturnValue { + // Given + val mockery = AsyncFunMockery Any>(fixture.fixture()) + val value: Any = fixture.fixture() + val values: List = fixture.listFixture() + val sideEffect: suspend () -> Any = { + fixture.fixture() + } + + mockery.returnValue = value + mockery.returnValues = values + mockery.sideEffect = sideEffect + + return runBlockingTestInContext(testScope2.coroutineContext) { + mockery.invoke() + + mockery.clear() + + mockery.returnValue mustBe null + + try { + mockery.returnValues + } catch (error: Throwable) { + (error is NullPointerException) mustBe true + } + + try { + mockery.sideEffect mustBe null + } catch (error: Throwable) { + (error is NullPointerException) mustBe true + } + + mockery.calls mustBe 0 + + try { + mockery.getArgumentsForCall(0) + } catch (error: Throwable) { + (error is IndexOutOfBoundsException) mustBe true + } + } + } + + @Test + @JsOnly + @JsName("fn49") + fun `Given clear is called it clears the mock for Js`(): AsyncTestReturnValue { + // Given + val mockery = AsyncFunMockery Any>(fixture.fixture()) + val value: Any = fixture.fixture() + val values: List = fixture.listFixture() + val sideEffect: suspend () -> Any = { + fixture.fixture() + } + + mockery.returnValue = value + mockery.returnValues = values + mockery.sideEffect = sideEffect + + return runBlockingTestInContext(testScope2.coroutineContext) { + mockery.invoke() + + mockery.clear() + + mockery.returnValue mustBe null + + try { + mockery.returnValues + } catch (error: Throwable) { + (error is ClassCastException) mustBe true + } + + try { + mockery.sideEffect mustBe null + } catch (error: Throwable) { + (error is ClassCastException) mustBe true + } + + mockery.calls mustBe 0 + + try { + mockery.getArgumentsForCall(0) + } catch (error: Throwable) { + (error is IndexOutOfBoundsException) mustBe true + } + } + } } diff --git a/kmock/src/commonTest/kotlin/tech/antibytes/kmock/MockeryAssertionSpec.kt b/kmock/src/commonTest/kotlin/tech/antibytes/kmock/MockeryAssertionSpec.kt new file mode 100644 index 00000000..b07492d2 --- /dev/null +++ b/kmock/src/commonTest/kotlin/tech/antibytes/kmock/MockeryAssertionSpec.kt @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2022 Matthias Geisler (bitPogo) / All rights reserved. + * + * Use of this source code is governed by Apache v2.0 + */ + +package tech.antibytes.kmock + +import tech.antibytes.mock.FunMockeryStub +import tech.antibytes.mock.PropertyMockeryStub +import tech.antibytes.util.test.fixture.fixture +import tech.antibytes.util.test.fixture.kotlinFixture +import tech.antibytes.util.test.fixture.listFixture +import kotlin.js.JsName +import kotlin.test.Test +import kotlin.test.assertFailsWith + +class MockeryAssertionSpec { + private val fixture = kotlinFixture() + + @Test + @JsName("fn0") + fun `Given assertWasCalled fails if the amount of calls does not match the criteria`() { + // Given + val values = fixture.listFixture(size = 2).toTypedArray() + val mockery = FunMockeryStub(fixture.fixture(), 5) + + mockery.getArgumentsForCall = { values } + + // Then + assertFailsWith { + // When + mockery.assertWasCalled(exactly = 1) + } + } + + @Test + @JsName("fn1") + fun `Given assertWasCalled accepts if the amount of calls match the criteria`() { + // Given + val values = fixture.listFixture(size = 2).toTypedArray() + val mockery = FunMockeryStub(fixture.fixture(), 1) + + mockery.getArgumentsForCall = { values } + + // When + mockery.assertWasCalled(exactly = 1) + } + + @Test + @JsName("fn2") + fun `Given assertWasCalledWith fails if the amount of calls does not match the criteria`() { + // Given + val values = fixture.listFixture(size = 2).toTypedArray() + val mockery = FunMockeryStub(fixture.fixture(), 1) + + mockery.getArgumentsForCall = { values } + + // Then + assertFailsWith { + // When + mockery.assertWasCalledWith( + exactly = 1, + arguments = fixture.listFixture().toTypedArray() + ) + } + } + + @Test + @JsName("fn3") + fun `Given assertWasCalledWith accepts if the amount of calls does match the criteria`() { + // Given + val values = fixture.listFixture(size = 2).toTypedArray() + val mockery = FunMockeryStub(fixture.fixture(), 1) + + mockery.getArgumentsForCall = { values } + // When + mockery.assertWasCalledWith( + exactly = 1, + values[0] + ) + } + + @Test + @JsName("fn4") + fun `Given assertWasCalledStrictlyWith fails if the amount of calls does not match the criteria`() { + // Given + val values = fixture.listFixture(size = 2).toTypedArray() + val mockery = FunMockeryStub(fixture.fixture(), 1) + + mockery.getArgumentsForCall = { values } + + // Then + assertFailsWith { + // When + mockery.assertWasCalledStrictlyWith( + exactly = 1, + values[0] + ) + } + } + + @Test + @JsName("fn5") + fun `Given assertWasCalledStrictlyWith accepts if the amount of calls does match the criteria`() { + // Given + val values = fixture.listFixture(size = 2).toTypedArray() + val mockery = FunMockeryStub(fixture.fixture(), 1) + + mockery.getArgumentsForCall = { values } + + // When + mockery.assertWasCalledStrictlyWith( + exactly = 1, + arguments = values + ) + } + + @Test + @JsName("fn6") + fun `Given assertWasNotCalled fails if the amount of calls does not match the criteria`() { + // Given + val values = fixture.listFixture(size = 2).toTypedArray() + val mockery = FunMockeryStub(fixture.fixture(), 1) + + mockery.getArgumentsForCall = { values } + + // Then + assertFailsWith { + // When + mockery.assertWasNotCalled() + } + } + + @Test + @JsName("fn7") + fun `Given assertWasNotCalled accepts if the amount of calls does match the criteria`() { + // Given + val values = fixture.listFixture(size = 2).toTypedArray() + val mockery = FunMockeryStub(fixture.fixture(), 0) + + mockery.getArgumentsForCall = { values } + + // When + mockery.assertWasNotCalled() + } + + @Test + @JsName("fn8") + fun `Given assertWasNotCalledWith fails if the amount of calls does not match the criteria`() { + // Given + val values = fixture.listFixture(size = 2).toTypedArray() + val mockery = FunMockeryStub(fixture.fixture(), 1) + + mockery.getArgumentsForCall = { values } + + // Then + assertFailsWith { + // When + mockery.assertWasNotCalledWith(values[0]) + } + } + + @Test + @JsName("fn9") + fun `Given assertWasNotCalledWith accepts if the amount of calls does match the criteria`() { + // Given + val values = fixture.listFixture(size = 2).toTypedArray() + val mockery = FunMockeryStub(fixture.fixture(), 1) + + mockery.getArgumentsForCall = { values } + + // When + mockery.assertWasNotCalledWith(fixture.fixture()) + } + + @Test + @JsName("fn10") + fun `Given assertWasCalledWithout fails if the amount of calls does not match the criteria`() { + // Given + val values = fixture.listFixture(size = 2).toTypedArray() + val mockery = FunMockeryStub(fixture.fixture(), 2) + + mockery.getArgumentsForCall = { values } + + // Then + assertFailsWith { + // When + mockery.assertWasCalledWithout(values[0]) + } + } + + @Test + @JsName("fn11") + fun `Given assertWasCalledWithout accepts if the amount of calls does match the criteria`() { + // Given + val values = fixture.listFixture(size = 2).toTypedArray() + val mockery = FunMockeryStub(fixture.fixture(), 2) + + mockery.getArgumentsForCall = { values } + + // When + mockery.assertWasCalledWithout(fixture.fixture()) + } + + @Test + @JsName("fn12") + fun `Given assertWasGotten fails if the amount of calls does not match the criteria`() { + // Given + val mockery = PropertyMockeryStub(fixture.fixture(), 2) + + mockery.getArgumentsForCall = { KMockContract.GetOrSet.Get } + + // Then + assertFailsWith { + // When + mockery.assertWasGotten(1) + } + } + + @Test + @JsName("fn13") + fun `Given assertWasGotten accepts if the amount of calls does match the criteria`() { + // Given + val mockery = PropertyMockeryStub(fixture.fixture(), 1) + + mockery.getArgumentsForCall = { KMockContract.GetOrSet.Get } + + // When + mockery.assertWasGotten(1) + } + + @Test + @JsName("fn14") + fun `Given assertWasSet fails if the amount of calls does not match the criteria`() { + // Given + val mockery = PropertyMockeryStub(fixture.fixture(), 2) + + mockery.getArgumentsForCall = { KMockContract.GetOrSet.Set(null) } + + // Then + assertFailsWith { + // When + mockery.assertWasSet(1) + } + } + + @Test + @JsName("fn15") + fun `Given assertWasSet accepts if the amount of calls does match the criteria`() { + // Given + val mockery = PropertyMockeryStub(fixture.fixture(), 1) + + mockery.getArgumentsForCall = { KMockContract.GetOrSet.Set(null) } + + // When + mockery.assertWasSet(1) + } + + @Test + @JsName("fn16") + fun `Given assertWasSetTo fails if the amount of calls does not match the criteria`() { + // Given + val mockery = PropertyMockeryStub(fixture.fixture(), 2) + + mockery.getArgumentsForCall = { KMockContract.GetOrSet.Set(fixture.fixture()) } + + // Then + assertFailsWith { + // When + mockery.assertWasSetTo(1, fixture.fixture()) + } + } + + @Test + @JsName("fn17") + fun `Given assertWasSetTo accepts if the amount of calls does match the criteria`() { + // Given + val value: Any = fixture.fixture() + val mockery = PropertyMockeryStub(fixture.fixture(), 1) + + mockery.getArgumentsForCall = { KMockContract.GetOrSet.Set(value) } + + // When + mockery.assertWasSetTo(1, value) + } +} diff --git a/kmock/src/commonTest/kotlin/tech/antibytes/kmock/PropertyMockerySpec.kt b/kmock/src/commonTest/kotlin/tech/antibytes/kmock/PropertyMockerySpec.kt index 3253e555..71cbc5cb 100644 --- a/kmock/src/commonTest/kotlin/tech/antibytes/kmock/PropertyMockerySpec.kt +++ b/kmock/src/commonTest/kotlin/tech/antibytes/kmock/PropertyMockerySpec.kt @@ -10,6 +10,8 @@ import co.touchlab.stately.concurrency.AtomicReference import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.launch import tech.antibytes.util.test.MockError +import tech.antibytes.util.test.annotations.IgnoreJs +import tech.antibytes.util.test.annotations.JsOnly import tech.antibytes.util.test.coroutine.AsyncTestReturnValue import tech.antibytes.util.test.coroutine.TestScopeDispatcher import tech.antibytes.util.test.coroutine.asyncMultiBlock @@ -19,6 +21,7 @@ import tech.antibytes.util.test.fixture.fixture import tech.antibytes.util.test.fixture.kotlinFixture import tech.antibytes.util.test.fixture.listFixture import tech.antibytes.util.test.fulfils +import tech.antibytes.util.test.isNot import tech.antibytes.util.test.mustBe import tech.antibytes.util.test.sameAs import kotlin.js.JsName @@ -442,4 +445,80 @@ class PropertyMockerySpec { return asyncMultiBlock } + + @Test + @IgnoreJs + @JsName("fn21") + fun `Given clear is called it clears the mock`() { + // Given + val mockery = PropertyMockery(fixture.fixture()) + val value: Any = fixture.fixture() + val values: List = fixture.listFixture() + val sideEffect: (Any) -> Unit = { } + + mockery.get = value + mockery.getMany = values + mockery.set = sideEffect + + mockery.onGet() + mockery.onSet(fixture.fixture()) + + mockery.clear() + + mockery.get mustBe null + + try { + mockery.getMany + } catch (error: Throwable) { + (error is NullPointerException) mustBe true + } + + mockery.set isNot sideEffect + + mockery.calls mustBe 0 + + try { + mockery.getArgumentsForCall(0) + } catch (error: Throwable) { + (error is IndexOutOfBoundsException) mustBe true + } + } + + @Test + @JsOnly + @JsName("fn22") + fun `Given clear is called it clears the mock for Js`() { + // Given + val mockery = PropertyMockery(fixture.fixture()) + val value: Any = fixture.fixture() + val values: List = fixture.listFixture() + val sideEffect: (Any) -> Unit = { } + + mockery.get = value + mockery.getMany = values + mockery.set = sideEffect + + mockery.onGet() + mockery.onSet(fixture.fixture()) + + mockery.clear() + + mockery.get mustBe null + + try { + mockery.getMany + } catch (error: Throwable) { + (error is ClassCastException) mustBe true + } + + mockery.set isNot sideEffect + + mockery.calls mustBe 0 + + try { + mockery.getArgumentsForCall(0) + } catch (error: Throwable) { + (error is IndexOutOfBoundsException) mustBe true + } + } } diff --git a/kmock/src/commonTest/kotlin/tech/antibytes/kmock/SyncFunMockerySpec.kt b/kmock/src/commonTest/kotlin/tech/antibytes/kmock/SyncFunMockerySpec.kt index f3382077..3637c159 100644 --- a/kmock/src/commonTest/kotlin/tech/antibytes/kmock/SyncFunMockerySpec.kt +++ b/kmock/src/commonTest/kotlin/tech/antibytes/kmock/SyncFunMockerySpec.kt @@ -11,6 +11,8 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.launch import tech.antibytes.kmock.KMockContract.Collector import tech.antibytes.util.test.MockError +import tech.antibytes.util.test.annotations.IgnoreJs +import tech.antibytes.util.test.annotations.JsOnly import tech.antibytes.util.test.coroutine.AsyncTestReturnValue import tech.antibytes.util.test.coroutine.TestScopeDispatcher import tech.antibytes.util.test.coroutine.asyncMultiBlock @@ -1403,4 +1405,92 @@ class SyncFunMockerySpec { return asyncMultiBlock } + + @Test + @IgnoreJs + @JsName("fn34") + fun `Given clear is called it clears the mock`() { + // Given + val mockery = SyncFunMockery Any>(fixture.fixture()) + val value: Any = fixture.fixture() + val values: List = fixture.listFixture() + val sideEffect: () -> Any = { + fixture.fixture() + } + + mockery.returnValue = value + mockery.returnValues = values + mockery.sideEffect = sideEffect + + // When + mockery.invoke() + + mockery.clear() + + // Then + mockery.returnValue mustBe null + try { + mockery.returnValues + } catch (error: Throwable) { + (error is NullPointerException) mustBe true + } + + try { + mockery.sideEffect mustBe null + } catch (error: Throwable) { + (error is NullPointerException) mustBe true + } + + mockery.calls mustBe 0 + + try { + mockery.getArgumentsForCall(0) + } catch (error: Throwable) { + (error is IndexOutOfBoundsException) mustBe true + } + } + + @Test + @JsOnly + @JsName("fn35") + fun `Given clear is called it clears the mock for Js`() { + // Given + val mockery = SyncFunMockery Any>(fixture.fixture()) + val value: Any = fixture.fixture() + val values: List = fixture.listFixture() + val sideEffect: () -> Any = { + fixture.fixture() + } + + mockery.returnValue = value + mockery.returnValues = values + mockery.sideEffect = sideEffect + + // When + mockery.invoke() + + mockery.clear() + + // Then + mockery.returnValue mustBe null + try { + mockery.returnValues + } catch (error: Throwable) { + (error is ClassCastException) mustBe true + } + + try { + mockery.sideEffect mustBe null + } catch (error: Throwable) { + (error is ClassCastException) mustBe true + } + + mockery.calls mustBe 0 + + try { + mockery.getArgumentsForCall(0) + } catch (error: Throwable) { + (error is IndexOutOfBoundsException) mustBe true + } + } } diff --git a/kmock/src/commonTest/kotlin/tech/antibytes/kmock/VerificationChainBuilderSpec.kt b/kmock/src/commonTest/kotlin/tech/antibytes/kmock/VerificationChainBuilderSpec.kt index fae433ab..49bb679e 100644 --- a/kmock/src/commonTest/kotlin/tech/antibytes/kmock/VerificationChainBuilderSpec.kt +++ b/kmock/src/commonTest/kotlin/tech/antibytes/kmock/VerificationChainBuilderSpec.kt @@ -77,7 +77,7 @@ class VerificationChainBuilderSpec { // When val container = VerificationChainBuilder() - container.withArguments(mock, *(values.sorted()).toTypedArray()) + container.wasCalledWithArguments(mock, *(values.sorted()).toTypedArray()) // Then val actual = container.toList()[0] @@ -102,7 +102,7 @@ class VerificationChainBuilderSpec { // When val container = VerificationChainBuilder() - container.withSameArguments(mock, *values) + container.wasCalledWithArgumentsStrict(mock, *values) // Then val actual = container.toList()[0] @@ -126,7 +126,7 @@ class VerificationChainBuilderSpec { // When val container = VerificationChainBuilder() - container.withoutArguments(mock, fixture.fixture()) + container.wasCalledWithoutArguments(mock, fixture.fixture()) // Then val actual = container.toList()[0] diff --git a/kmock/src/commonTest/kotlin/tech/antibytes/kmock/VerificationFactorySpec.kt b/kmock/src/commonTest/kotlin/tech/antibytes/kmock/VerificationHandleFactorySpec.kt similarity index 79% rename from kmock/src/commonTest/kotlin/tech/antibytes/kmock/VerificationFactorySpec.kt rename to kmock/src/commonTest/kotlin/tech/antibytes/kmock/VerificationHandleFactorySpec.kt index bde80f03..b76a0610 100644 --- a/kmock/src/commonTest/kotlin/tech/antibytes/kmock/VerificationFactorySpec.kt +++ b/kmock/src/commonTest/kotlin/tech/antibytes/kmock/VerificationHandleFactorySpec.kt @@ -15,18 +15,18 @@ import tech.antibytes.util.test.mustBe import kotlin.js.JsName import kotlin.test.Test -class VerificationFactorySpec { +class VerificationHandleFactorySpec { private val fixture = kotlinFixture() @Test @JsName("fn0") - fun `Given withArguments is called with a FunMockery it returns a VerficationHandle which contains no matches if nothing matches`() { + fun `Given wasCalledWithArguments is called with a FunMockery it returns a VerficationHandle which contains no matches if nothing matches`() { // Given val name: String = fixture.fixture() val mock = FunMockeryStub(name, 0) // When - val actual = mock.withArguments() + val actual = mock.wasCalledWithArguments() // Then actual mustBe VerificationHandle(name, emptyList()) @@ -34,7 +34,7 @@ class VerificationFactorySpec { @Test @JsName("fn1") - fun `Given withArguments is called with a FunMockery it returns a VerficationHandle which contains no matches if nothing matches while delegating the captured values`() { + fun `Given wasCalledWithArguments is called with a FunMockery it returns a VerficationHandle which contains no matches if nothing matches while delegating the captured values`() { // Given val name: String = fixture.fixture() val mock = FunMockeryStub(name, 1) @@ -47,7 +47,7 @@ class VerificationFactorySpec { } // When - val actual = mock.withArguments(fixture.fixture()) + val actual = mock.wasCalledWithArguments(fixture.fixture()) // Then actual mustBe VerificationHandle(name, emptyList()) @@ -56,7 +56,7 @@ class VerificationFactorySpec { @Test @JsName("fn2") - fun `Given withArguments is called with a FunMockery it returns a VerficationHandle which contains matches if something matches while delegating the captured values`() { + fun `Given wasCalledWithArguments is called with a FunMockery it returns a VerficationHandle which contains matches if something matches while delegating the captured values`() { // Given val name: String = fixture.fixture() val mock = FunMockeryStub(name, 1) @@ -70,7 +70,7 @@ class VerificationFactorySpec { } // When - val actual = mock.withArguments(*(values.sorted()).toTypedArray()) + val actual = mock.wasCalledWithArguments(*(values.sorted()).toTypedArray()) // Then actual mustBe VerificationHandle(name, listOf(0)) @@ -79,13 +79,13 @@ class VerificationFactorySpec { @Test @JsName("fn4") - fun `Given withSameArguments is called with a FunMockery it returns a VerficationHandle which contains no matches if nothing matches`() { + fun `Given wasCalledWithArgumentsStrict is called with a FunMockery it returns a VerficationHandle which contains no matches if nothing matches`() { // Given val name: String = fixture.fixture() val mock = FunMockeryStub(name, 0) // When - val actual = mock.withSameArguments() + val actual = mock.wasCalledWithArgumentsStrict() // Then actual mustBe VerificationHandle(name, emptyList()) @@ -93,7 +93,7 @@ class VerificationFactorySpec { @Test @JsName("fn5") - fun `Given withSameArguments is called with a FunMockery it returns a VerficationHandle which contains no matches if nothing matches while delegating the captured values`() { + fun `Given wasCalledWithArgumentsStrict is called with a FunMockery it returns a VerficationHandle which contains no matches if nothing matches while delegating the captured values`() { // Given val name: String = fixture.fixture() val mock = FunMockeryStub(name, 1) @@ -106,7 +106,7 @@ class VerificationFactorySpec { } // When - val actual = mock.withSameArguments(fixture.fixture()) + val actual = mock.wasCalledWithArgumentsStrict(fixture.fixture()) // Then actual mustBe VerificationHandle(name, emptyList()) @@ -115,7 +115,7 @@ class VerificationFactorySpec { @Test @JsName("fn6") - fun `Given withSameArguments is called with a FunMockery it returns a VerficationHandle which contains matches if something matches while delegating the captured values`() { + fun `Given wasCalledWithArgumentsStrict is called with a FunMockery it returns a VerficationHandle which contains matches if something matches while delegating the captured values`() { // Given val name: String = fixture.fixture() val mock = FunMockeryStub(name, 1) @@ -129,7 +129,7 @@ class VerificationFactorySpec { } // When - val actual = mock.withSameArguments(*values) + val actual = mock.wasCalledWithArgumentsStrict(*values) // Then actual mustBe VerificationHandle(name, listOf(0)) @@ -138,13 +138,13 @@ class VerificationFactorySpec { @Test @JsName("fn7") - fun `Given withoutArguments is called with a FunMockery it returns a VerficationHandle which contains no matches if nothing matches`() { + fun `Given wasCalledWithoutArguments is called with a FunMockery it returns a VerficationHandle which contains no matches if nothing matches`() { // Given val name: String = fixture.fixture() val mock = FunMockeryStub(name, 0) // When - val actual = mock.withoutArguments() + val actual = mock.wasCalledWithoutArguments() // Then actual mustBe VerificationHandle(name, emptyList()) @@ -152,7 +152,7 @@ class VerificationFactorySpec { @Test @JsName("fn8") - fun `Given withoutArguments is called with a FunMockery it returns a VerficationHandle which contains no matches if nothing matches while delegating the captured values`() { + fun `Given wasCalledWithoutArguments is called with a FunMockery it returns a VerficationHandle which contains no matches if nothing matches while delegating the captured values`() { // Given val name: String = fixture.fixture() val mock = FunMockeryStub(name, 1) @@ -166,7 +166,7 @@ class VerificationFactorySpec { } // When - val actual = mock.withoutArguments(*values) + val actual = mock.wasCalledWithoutArguments(*values) // Then actual mustBe VerificationHandle(name, emptyList()) @@ -175,7 +175,7 @@ class VerificationFactorySpec { @Test @JsName("fn9") - fun `Given withoutArguments is called with a FunMockery it returns a VerficationHandle which contains matches if something matches while delegating the captured values`() { + fun `Given wasCalledWithoutArguments is called with a FunMockery it returns a VerficationHandle which contains matches if something matches while delegating the captured values`() { // Given val name: String = fixture.fixture() val mock = FunMockeryStub(name, 1) @@ -188,7 +188,7 @@ class VerificationFactorySpec { } // When - val actual = mock.withoutArguments(fixture.fixture()) + val actual = mock.wasCalledWithoutArguments(fixture.fixture()) // Then actual mustBe VerificationHandle(name, listOf(0)) diff --git a/kmock/src/commonTest/kotlin/tech/antibytes/kmock/VerifierSpec.kt b/kmock/src/commonTest/kotlin/tech/antibytes/kmock/VerifierSpec.kt index 782a3a18..80426a89 100644 --- a/kmock/src/commonTest/kotlin/tech/antibytes/kmock/VerifierSpec.kt +++ b/kmock/src/commonTest/kotlin/tech/antibytes/kmock/VerifierSpec.kt @@ -65,4 +65,20 @@ class VerifierSpec { return asyncMultiBlock } + + @Test + @JsName("fn4") + fun `Given clear is called it clears the verifier`() { + // Given + val mockery = FunMockeryStub(fixture.fixture(), fixture.fixture()) + val verifier = Verifier() + + // When + verifier.addReference(mockery, fixture.fixture()) + + verifier.clear() + + // Then + verifier.references mustBe emptyList() + } }