kotlin-test: assertIs and assertIsNot KT-45296

- Rename assertNotIs to assertIsNot
- Extract parts of implementation to helper internal PublishedApi
functions in order to inline minimum amount of code at use sites
- Remove PublishedApi from messagePrefix, no longer needed
This commit is contained in:
Ilya Gorbunov
2021-03-17 13:53:33 +03:00
parent 3a0219d84c
commit e66eeefe2a
3 changed files with 38 additions and 19 deletions
@@ -17,6 +17,7 @@ import kotlin.internal.*
import kotlin.jvm.JvmName
import kotlin.native.concurrent.ThreadLocal
import kotlin.reflect.KClass
import kotlin.reflect.KType
import kotlin.reflect.typeOf
/**
@@ -80,26 +81,38 @@ fun <@OnlyInputTypes T> assertNotSame(illegal: T, actual: T, message: String? =
/**
* Asserts that [value] is of type [T], with an optional [message].
*
* Note that due to type erasure the type check may be partial (e.g. assertIs<List<String>>(value)
* Note that due to type erasure the type check may be partial (e.g. `assertIs<List<String>>(value)`
* only checks for the class being [List] and not the type of its elements because it's erased).
*/
@SinceKotlin("1.5")
@InlineOnly
@OptIn(ExperimentalStdlibApi::class)
inline fun <reified T> assertIs(value: Any?, message: String? = null) {
contract { returns() implies (value is T) }
asserter.assertTrue({ messagePrefix(message) + "Expected value to be of type <${typeOf<T>()}>, actual <${value?.let { it::class }}>." }, value is T)
assertIsOfType(value, typeOf<T>(), value is T, message)
}
@PublishedApi
internal fun assertIsOfType(value: Any?, type: KType, result: Boolean, message: String?) {
asserter.assertTrue({ messagePrefix(message) + "Expected value to be of type <$type>, actual <${value?.let { it::class }}>." }, result)
}
/**
* Asserts that [value] is not of type [T], with an optional [message].
*
* Note that due to type erasure the type check may be partial (e.g. assertNotIs<List<String>>(value)
* Note that due to type erasure the type check may be partial (e.g. `assertIsNot<List<String>>(value)`
* only checks for the class being [List] and not the type of its elements because it's erased).
*/
@SinceKotlin("1.5")
@InlineOnly
inline fun <reified T> assertNotIs(value: Any?, message: String? = null) {
asserter.assertFalse({ messagePrefix(message) + "Expected value to not be of type <${typeOf<T>()}>" }, value is T)
@OptIn(ExperimentalStdlibApi::class)
inline fun <reified T> assertIsNot(value: Any?, message: String? = null) {
assertIsNotOfType(value, typeOf<T>(), value !is T, message)
}
@PublishedApi
internal fun assertIsNotOfType(@Suppress("UNUSED_PARAMETER") value: Any?, type: KType, result: Boolean, message: String?) {
asserter.assertTrue({ messagePrefix(message) + "Expected value to not be of type <$type>." }, result)
}
/** Asserts that the [actual] value is not `null`, with an optional [message]. */
@@ -1,11 +1,10 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlin.test
@PublishedApi // called from inline assert functions
internal fun messagePrefix(message: String?) = if (message == null) "" else "$message. "
internal expect fun lookupAsserter(): Asserter
@@ -1,10 +1,11 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlin.test.tests
import kotlin.reflect.typeOf
import kotlin.test.*
class BasicAssertionsTest {
@@ -207,30 +208,36 @@ class BasicAssertionsTest {
}
@Test
fun testAssertIs() {
fun testAssertIsOfType() {
val s: Any = "test"
assertIs<String>(s)
assertEquals(4, s.length)
}
@OptIn(ExperimentalStdlibApi::class)
@Test
fun testAssertIsFails() {
fun testAssertIsOfTypeFails() {
val error = checkFailedAssertion { assertIs<Int>("test") }
assertTrue(error.message.startsWith("Expected value to be of type"))
assertTrue(error.message.contains("Int"))
assertTrue(error.message.contains("String"))
val message = assertNotNull(error.message)
val onFailure = "Actual message: $message"
assertTrue(message.startsWith("Expected value to be of type"), onFailure)
assertTrue(message.contains(typeOf<Int>().toString()), onFailure)
assertTrue(message.contains("String"), onFailure)
}
@Test
fun testAssertNotIs() {
assertNotIs<Int>("test")
fun testAssertIsNotOfType() {
assertIsNot<Int>("test")
}
@Test
fun testAssertNotIsFails() {
val error = checkFailedAssertion { assertNotIs<Int>(1) }
assertTrue(error.message.startsWith("Expected value to not be of type"))
assertTrue(error.message.contains("Int"))
@OptIn(ExperimentalStdlibApi::class)
fun testAssertIsNotOfTypeFails() {
val error = checkFailedAssertion { assertIsNot<Int>(1) }
val message = assertNotNull(error.message)
val onFailure = "Actual message: $message"
assertTrue(message.startsWith("Expected value to not be of type"), onFailure)
assertTrue(message.contains(typeOf<Int>().toString()), onFailure)
}
}