unit-tests: Assert library
This commit is contained in:
+2
-2
@@ -532,9 +532,9 @@ internal class TestProcessor (val context: KonanBackendContext): FileLoweringPas
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// TODO: Get tests from Kotlin/JVM
|
||||
// TODO: Support tests in objects
|
||||
// TODO: Support beforeTest/afterTest for companions.
|
||||
// TODO: Check beforeTest/afterTest for companions.
|
||||
private fun createTestSuites(irFile: IrFile, annotationCollector: AnnotationCollector) {
|
||||
annotationCollector.testClasses.filter {
|
||||
it.value.functions.any { it.kind == FunctionKind.TEST }
|
||||
|
||||
@@ -92,4 +92,9 @@ public annotation class Fixme
|
||||
|
||||
public annotation class Escapes(val who: Int)
|
||||
|
||||
public annotation class PointsTo(vararg val onWhom: Int)
|
||||
public annotation class PointsTo(vararg val onWhom: Int)
|
||||
|
||||
/**
|
||||
* Need to be fixed because of header/impl notation
|
||||
*/
|
||||
public annotation class FixmeMultiplatform
|
||||
|
||||
@@ -9,8 +9,8 @@ interface TestListener {
|
||||
fun startSuite(suite: TestSuite)
|
||||
fun endSuite(suite: TestSuite)
|
||||
|
||||
fun start(testCase: TestCase)
|
||||
fun pass(testCase: TestCase)
|
||||
fun fail(testCase: TestCase, e: AssertionError)
|
||||
fun error(testCase: TestCase, e: Throwable)
|
||||
fun fail(testCase: TestCase, e: Throwable)
|
||||
fun ignore(testCase: TestCase)
|
||||
}
|
||||
@@ -1,20 +1,21 @@
|
||||
package konan.test
|
||||
|
||||
import kotlin.AssertionError
|
||||
|
||||
object TestRunner {
|
||||
|
||||
object SimpleTestListener: TestListener {
|
||||
override fun startTesting(runner: TestRunner) = println("Starting testing\n")
|
||||
override fun endTesting(runner: TestRunner) = println("Testing finished\n")
|
||||
override fun startTesting(runner: TestRunner) = println("Starting testing")
|
||||
override fun endTesting(runner: TestRunner) = println("Testing finished")
|
||||
|
||||
override fun startSuite(suite: TestSuite) = println("Starting test suite: $suite\n")
|
||||
override fun endSuite(suite: TestSuite) = println("Test suite finished: $suite\n")
|
||||
override fun startSuite(suite: TestSuite) = println("Starting test suite: $suite")
|
||||
override fun endSuite(suite: TestSuite) = println("Test suite finished: $suite")
|
||||
|
||||
override fun pass(testCase: TestCase) = println("Pass: $testCase\n")
|
||||
override fun fail(testCase: TestCase, e: AssertionError) = println("Fail: $testCase (Exception: ${e.message})\n")
|
||||
override fun error(testCase: TestCase, e: Throwable) = println("Error: $testCase (Exception: ${e.message})\n")
|
||||
override fun ignore(testCase: TestCase) = println("Ignore: $testCase\n")
|
||||
override fun start(testCase: TestCase) = println("Start test case: $testCase")
|
||||
override fun pass(testCase: TestCase) = println("Pass: $testCase")
|
||||
override fun fail(testCase: TestCase, e: Throwable) {
|
||||
println("Fail: $testCase. Exception:")
|
||||
e.printStackTrace()
|
||||
}
|
||||
override fun ignore(testCase: TestCase) = println("Ignore: $testCase")
|
||||
}
|
||||
|
||||
private val _suites = mutableListOf<TestSuite>()
|
||||
|
||||
@@ -29,7 +29,7 @@ abstract class AbstractTestSuite<F: Function<Unit>>(override val name: String):
|
||||
override val suite: AbstractTestSuite<F>,
|
||||
val testFunction: F
|
||||
) : TestCase {
|
||||
override fun toString(): String = "$suite.$name"
|
||||
override fun toString(): String = "$name ($suite)"
|
||||
}
|
||||
|
||||
private val _testCases = mutableMapOf<String, BasicTestCase<F>>()
|
||||
@@ -53,13 +53,11 @@ abstract class AbstractTestSuite<F: Function<Unit>>(override val name: String):
|
||||
doBeforeClass()
|
||||
testCases.values.forEach {
|
||||
try {
|
||||
listener.start(it)
|
||||
doTest(it)
|
||||
listener.pass(it)
|
||||
// TODO: merge catches?
|
||||
} catch (e: AssertionError) {
|
||||
listener.fail(it, e)
|
||||
} catch (e: Throwable) {
|
||||
listener.error(it, e)
|
||||
listener.fail(it, e)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package kotlin.test
|
||||
|
||||
// TODO: Move test code in a separate library.
|
||||
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
annotation class Test
|
||||
@@ -14,6 +12,7 @@ annotation class BeforeClass
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
annotation class AfterClass
|
||||
|
||||
// TODO: Rename Before -> BeforeEach, After -> AfterEach
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
annotation class Before
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A number of common helper methods for writing unit tests. Copied from Kotlin repo.
|
||||
*/
|
||||
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
|
||||
package kotlin.test
|
||||
|
||||
import konan.FixmeMultiplatform
|
||||
import konan.FixmeReflection
|
||||
import kotlin.internal.InlineOnly
|
||||
import kotlin.internal.OnlyInputTypes
|
||||
|
||||
/**
|
||||
* Current adapter providing assertion implementations
|
||||
*/
|
||||
val asserter: Asserter
|
||||
get() = _asserter ?: lookupAsserter()
|
||||
|
||||
/** Used to override current asserter internally */
|
||||
internal var _asserter: Asserter? = null
|
||||
|
||||
/** Asserts that the given [block] returns `true`. */
|
||||
fun assertTrue(message: String? = null, block: () -> Boolean): Unit = assertTrue(block(), message)
|
||||
|
||||
/** Asserts that the expression is `true` with an optional [message]. */
|
||||
fun assertTrue(actual: Boolean, message: String? = null) {
|
||||
return asserter.assertTrue(message ?: "Expected value to be true.", actual)
|
||||
}
|
||||
|
||||
/** Asserts that the given [block] returns `false`. */
|
||||
fun assertFalse(message: String? = null, block: () -> Boolean): Unit = assertFalse(block(), message)
|
||||
|
||||
/** Asserts that the expression is `false` with an optional [message]. */
|
||||
fun assertFalse(actual: Boolean, message: String? = null) {
|
||||
return asserter.assertTrue(message ?: "Expected value to be false.", !actual)
|
||||
}
|
||||
|
||||
/** Asserts that the [expected] value is equal to the [actual] value, with an optional [message]. */
|
||||
fun <@OnlyInputTypes T> assertEquals(expected: T, actual: T, message: String? = null) {
|
||||
asserter.assertEquals(message, expected, actual)
|
||||
}
|
||||
|
||||
/** Asserts that the [actual] value is not equal to the illegal value, with an optional [message]. */
|
||||
fun <@OnlyInputTypes T> assertNotEquals(illegal: T, actual: T, message: String? = null) {
|
||||
asserter.assertNotEquals(message, illegal, actual)
|
||||
}
|
||||
|
||||
/** Asserts that the [actual] value is not `null`, with an optional [message]. */
|
||||
fun <T : Any> assertNotNull(actual: T?, message: String? = null): T {
|
||||
asserter.assertNotNull(message, actual)
|
||||
return actual!!
|
||||
}
|
||||
|
||||
/** Asserts that the [actual] value is not `null`, with an optional [message] and a function [block] to process the not-null value. */
|
||||
fun <T : Any, R> assertNotNull(actual: T?, message: String? = null, block: (T) -> R) {
|
||||
asserter.assertNotNull(message, actual)
|
||||
if (actual != null) {
|
||||
block(actual)
|
||||
}
|
||||
}
|
||||
|
||||
/** Asserts that the [actual] value is `null`, with an optional [message]. */
|
||||
fun assertNull(actual: Any?, message: String? = null) {
|
||||
asserter.assertNull(message, actual)
|
||||
}
|
||||
|
||||
/** Marks a test as having failed if this point in the execution path is reached, with an optional [message]. */
|
||||
fun fail(message: String? = null): Nothing {
|
||||
asserter.fail(message)
|
||||
}
|
||||
|
||||
/** Asserts that given function [block] returns the given [expected] value. */
|
||||
fun <@OnlyInputTypes T> expect(expected: T, block: () -> T) {
|
||||
assertEquals(expected, block())
|
||||
}
|
||||
|
||||
/** Asserts that given function [block] returns the given [expected] value and use the given [message] if it fails. */
|
||||
fun <@OnlyInputTypes T> expect(expected: T, message: String?, block: () -> T) {
|
||||
assertEquals(expected, block(), message)
|
||||
}
|
||||
|
||||
/** Asserts that given function [block] fails by throwing an exception. */
|
||||
fun assertFails(block: () -> Unit): Throwable = assertFails(null, block)
|
||||
|
||||
/** Asserts that given function [block] fails by throwing an exception. */
|
||||
@SinceKotlin("1.1")
|
||||
fun assertFails(message: String?, block: () -> Unit): Throwable {
|
||||
try {
|
||||
block()
|
||||
} catch (e: Throwable) {
|
||||
assertEquals(e.message, e.message) // success path assertion for qunit
|
||||
return e
|
||||
}
|
||||
asserter.fail(messagePrefix(message) + "Expected an exception to be thrown, but was completed successfully.")
|
||||
}
|
||||
|
||||
/** Asserts that a [block] fails with a specific exception of type [T] being thrown.
|
||||
* Since inline method doesn't allow to trace where it was invoked, it is required to pass a [message] to distinguish this method call from others.
|
||||
*/
|
||||
@InlineOnly
|
||||
@FixmeReflection // TODO: Implement as in Kotlin/JVM when KClass is available.
|
||||
// TODO: An incorrect llvm module is generated if this method is called. Uncomment it when
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
inline fun <reified T : Throwable> assertFailsWith(message: String? = null, noinline block: () -> Unit) /*: T*/ {
|
||||
// try {
|
||||
// block()
|
||||
// } catch (e: Throwable) {
|
||||
// if (e is T) {
|
||||
// return e
|
||||
// }
|
||||
//
|
||||
// @Suppress("INVISIBLE_MEMBER")
|
||||
// asserter.fail(messagePrefix(message) + "Unxepected exception type: $e")
|
||||
// }
|
||||
//
|
||||
// @Suppress("INVISIBLE_MEMBER")
|
||||
// val msg = messagePrefix(message)
|
||||
// asserter.fail(msg + "Expected an exception to be thrown, but was completed successfully.")
|
||||
}
|
||||
|
||||
/** Asserts that a [block] fails with a specific exception of type [exceptionClass] being thrown. */
|
||||
//@FixmeReflection
|
||||
//fun <T : Throwable> assertFailsWith(exceptionClass: KClass<T>, block: () -> Unit): T = assertFailsWith(exceptionClass, null, block)
|
||||
|
||||
|
||||
// From AssertionsH.kt
|
||||
/**
|
||||
* Comments out a block of test code until it is implemented while keeping a link to the code
|
||||
* to implement in your unit test output
|
||||
*/
|
||||
@FixmeMultiplatform
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
/*header */ inline fun todo(block: () -> Unit) {
|
||||
println("TODO")
|
||||
}
|
||||
|
||||
/** Asserts that a [block] fails with a specific exception of type [exceptionClass] being thrown. */
|
||||
//@FixmeMultiplatform
|
||||
//@FixmeReflection
|
||||
//header fun <T : Throwable> assertFailsWith(exceptionClass: KClass<T>, message: String?, block: () -> Unit): T
|
||||
|
||||
// From Assertions.kt
|
||||
/**
|
||||
* Abstracts the logic for performing assertions.
|
||||
*/
|
||||
interface Asserter {
|
||||
/**
|
||||
* Fails the current test with the specified message.
|
||||
*
|
||||
* @param message the message to report.
|
||||
*/
|
||||
fun fail(message: String?): Nothing
|
||||
|
||||
/**
|
||||
* Asserts that the specified value is `true`.
|
||||
*
|
||||
* @param lazyMessage the function to return a message to report if the assertion fails.
|
||||
*/
|
||||
fun assertTrue(lazyMessage: () -> String?, actual: Boolean): Unit {
|
||||
if (!actual) {
|
||||
fail(lazyMessage())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the specified value is `true`.
|
||||
*
|
||||
* @param message the message to report if the assertion fails.
|
||||
*/
|
||||
fun assertTrue(message: String?, actual: Boolean): Unit {
|
||||
assertTrue({ message }, actual)
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the specified values are equal.
|
||||
*
|
||||
* @param message the message to report if the assertion fails.
|
||||
*/
|
||||
fun assertEquals(message: String?, expected: Any?, actual: Any?): Unit {
|
||||
assertTrue({ messagePrefix(message) + "Expected <$expected>, actual <$actual>." }, actual == expected)
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the specified values are not equal.
|
||||
*
|
||||
* @param message the message to report if the assertion fails.
|
||||
*/
|
||||
fun assertNotEquals(message: String?, illegal: Any?, actual: Any?): Unit {
|
||||
assertTrue({ messagePrefix(message) + "Illegal value: <$actual>." }, actual != illegal)
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the specified value is `null`.
|
||||
*
|
||||
* @param message the message to report if the assertion fails.
|
||||
*/
|
||||
fun assertNull(message: String?, actual: Any?): Unit {
|
||||
assertTrue({ messagePrefix(message) + "Expected value to be null, but was: <$actual>." }, actual == null)
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the specified value is not `null`.
|
||||
*
|
||||
* @param message the message to report if the assertion fails.
|
||||
*/
|
||||
fun assertNotNull(message: String?, actual: Any?): Unit {
|
||||
assertTrue({ messagePrefix(message) + "Expected value to be not null." }, actual != null)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks applicability and provides Asserter instance
|
||||
*/
|
||||
interface AsserterContributor {
|
||||
/**
|
||||
* Provides [Asserter] instance or `null` depends on the current context.
|
||||
*
|
||||
* @return asserter instance or null if it is not applicable now
|
||||
*/
|
||||
fun contribute(): Asserter?
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package kotlin.test
|
||||
|
||||
/**
|
||||
* Default [Asserter] implementation for Kotlin/Native.
|
||||
*/
|
||||
object DefaultAsserter : Asserter {
|
||||
override fun fail(message: String?): Nothing {
|
||||
if (message == null)
|
||||
throw AssertionError()
|
||||
else
|
||||
throw AssertionError(message)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package kotlin.test
|
||||
|
||||
@PublishedApi
|
||||
internal fun messagePrefix(message: String?) = if (message == null) "" else "$message. "
|
||||
|
||||
internal fun lookupAsserter(): Asserter = DefaultAsserter
|
||||
|
||||
@PublishedApi // required to get stable name as it's called from box tests
|
||||
internal fun overrideAsserter(value: Asserter?): Asserter? = _asserter.also { _asserter = value }
|
||||
Reference in New Issue
Block a user