[Test] Handle any Throwable from test instead of AssertionError

This commit is contained in:
Dmitriy Novozhilov
2021-01-22 12:34:56 +03:00
parent c111c33950
commit 42f9442728
11 changed files with 21 additions and 17 deletions
@@ -44,7 +44,7 @@ abstract class Assertions {
return collection.joinToString("\n") return collection.joinToString("\n")
} }
abstract fun assertAll(exceptions: List<AssertionError>) abstract fun assertAll(exceptions: List<Throwable>)
abstract fun fail(message: () -> String): Nothing abstract fun fail(message: () -> String): Nothing
} }
@@ -8,4 +8,7 @@ package org.jetbrains.kotlin.test
class ExceptionFromTestError(cause: Throwable) : AssertionError(cause) { class ExceptionFromTestError(cause: Throwable) : AssertionError(cause) {
override val message: String override val message: String
get() = "Exception was thrown" get() = "Exception was thrown"
override val cause: Throwable
get() = super.cause!!
} }
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.test.services.*
import java.io.IOException import java.io.IOException
class TestRunner(private val testConfiguration: TestConfiguration) { class TestRunner(private val testConfiguration: TestConfiguration) {
private val failedAssertions = mutableListOf<AssertionError>() private val failedAssertions = mutableListOf<Throwable>()
fun runTest(@TestDataFile testDataFileName: String) { fun runTest(@TestDataFile testDataFileName: String) {
try { try {
@@ -79,9 +79,10 @@ class TestRunner(private val testConfiguration: TestConfiguration) {
} }
val filteredFailedAssertions = testConfiguration.afterAnalysisCheckers val filteredFailedAssertions = testConfiguration.afterAnalysisCheckers
.fold<AfterAnalysisChecker, List<AssertionError>>(failedAssertions) { assertions, checker -> .fold<AfterAnalysisChecker, List<Throwable>>(failedAssertions) { assertions, checker ->
checker.suppressIfNeeded(assertions) checker.suppressIfNeeded(assertions)
} }
.map { if (it is ExceptionFromTestError) it.cause else it }
services.assertions.assertAll(filteredFailedAssertions) services.assertions.assertAll(filteredFailedAssertions)
} }
@@ -134,7 +135,7 @@ class TestRunner(private val testConfiguration: TestConfiguration) {
private inline fun withAssertionCatching(insertExceptionInStart: Boolean = false, block: () -> Unit) { private inline fun withAssertionCatching(insertExceptionInStart: Boolean = false, block: () -> Unit) {
try { try {
block() block()
} catch (e: AssertionError) { } catch (e: Throwable) {
if (insertExceptionInStart) { if (insertExceptionInStart) {
failedAssertions.add(0, e) failedAssertions.add(0, e)
} else { } else {
@@ -12,7 +12,7 @@ abstract class AfterAnalysisChecker(protected val testServices: TestServices) {
open val directives: List<DirectivesContainer> open val directives: List<DirectivesContainer>
get() = emptyList() get() = emptyList()
open fun check(failedAssertions: List<AssertionError>) {} open fun check(failedAssertions: List<Throwable>) {}
open fun suppressIfNeeded(failedAssertions: List<AssertionError>): List<AssertionError> = failedAssertions open fun suppressIfNeeded(failedAssertions: List<Throwable>): List<Throwable> = failedAssertions
} }
@@ -22,7 +22,7 @@ class BlackBoxCodegenSuppressor(testServices: TestServices) : AfterAnalysisCheck
override val directives: List<DirectivesContainer> override val directives: List<DirectivesContainer>
get() = listOf(CodegenTestDirectives) get() = listOf(CodegenTestDirectives)
override fun suppressIfNeeded(failedAssertions: List<AssertionError>): List<AssertionError> { override fun suppressIfNeeded(failedAssertions: List<Throwable>): List<Throwable> {
val moduleStructure = testServices.moduleStructure val moduleStructure = testServices.moduleStructure
val targetBackends = moduleStructure.modules.mapNotNull { it.targetBackend } val targetBackends = moduleStructure.modules.mapNotNull { it.targetBackend }
return when (moduleStructure.modules.map { it.frontendKind }.first()) { return when (moduleStructure.modules.map { it.frontendKind }.first()) {
@@ -36,8 +36,8 @@ class BlackBoxCodegenSuppressor(testServices: TestServices) : AfterAnalysisCheck
moduleStructure: TestModuleStructure, moduleStructure: TestModuleStructure,
directive: ValueDirective<TargetBackend>, directive: ValueDirective<TargetBackend>,
targetBackends: List<TargetBackend>, targetBackends: List<TargetBackend>,
failedAssertions: List<AssertionError> failedAssertions: List<Throwable>
): List<AssertionError> { ): List<Throwable> {
val ignoredBackends = moduleStructure.allDirectives[directive] val ignoredBackends = moduleStructure.allDirectives[directive]
if (ignoredBackends.isEmpty()) return failedAssertions if (ignoredBackends.isEmpty()) return failedAssertions
val matchedBackend = ignoredBackends.intersect(targetBackends) val matchedBackend = ignoredBackends.intersect(targetBackends)
@@ -52,10 +52,10 @@ class BlackBoxCodegenSuppressor(testServices: TestServices) : AfterAnalysisCheck
private fun processAssertions( private fun processAssertions(
failedAssertions: List<AssertionError>, failedAssertions: List<Throwable>,
directive: ValueDirective<TargetBackend>, directive: ValueDirective<TargetBackend>,
additionalMessage: String = "" additionalMessage: String = ""
): List<AssertionError> { ): List<Throwable> {
return if (failedAssertions.isNotEmpty()) emptyList() return if (failedAssertions.isNotEmpty()) emptyList()
else { else {
val message = buildString { val message = buildString {
@@ -39,7 +39,7 @@ class FirIrDumpIdenticalChecker(testServices: TestServices) : AfterAnalysisCheck
} }
} }
override fun check(failedAssertions: List<AssertionError>) { override fun check(failedAssertions: List<Throwable>) {
if (failedAssertions.isNotEmpty()) return if (failedAssertions.isNotEmpty()) return
val testDataFile = testServices.moduleStructure.originalTestDataFiles.first() val testDataFile = testServices.moduleStructure.originalTestDataFiles.first()
if (FIR_IDENTICAL in testServices.moduleStructure.allDirectives) { if (FIR_IDENTICAL in testServices.moduleStructure.allDirectives) {
@@ -21,7 +21,7 @@ class FirTestDataConsistencyHandler(testServices: TestServices) : AfterAnalysisC
override val directives: List<DirectivesContainer> override val directives: List<DirectivesContainer>
get() = listOf(FirDiagnosticsDirectives) get() = listOf(FirDiagnosticsDirectives)
override fun check(failedAssertions: List<AssertionError>) { override fun check(failedAssertions: List<Throwable>) {
val moduleStructure = testServices.moduleStructure val moduleStructure = testServices.moduleStructure
val testData = moduleStructure.originalTestDataFiles.first() val testData = moduleStructure.originalTestDataFiles.first()
if (testData.extension == "kts") return if (testData.extension == "kts") return
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.moduleStructure import org.jetbrains.kotlin.test.services.moduleStructure
class FirFailingTestSuppressor(testServices: TestServices) : AfterAnalysisChecker(testServices) { class FirFailingTestSuppressor(testServices: TestServices) : AfterAnalysisChecker(testServices) {
override fun suppressIfNeeded(failedAssertions: List<AssertionError>): List<AssertionError> { override fun suppressIfNeeded(failedAssertions: List<Throwable>): List<Throwable> {
val testFile = testServices.moduleStructure.originalTestDataFiles.first() val testFile = testServices.moduleStructure.originalTestDataFiles.first()
val failFile = testFile.parentFile.resolve("${testFile.nameWithoutExtension}.fail") val failFile = testFile.parentFile.resolve("${testFile.nameWithoutExtension}.fail")
val exceptionFromFir = failedAssertions.firstOrNull { it is ExceptionFromTestError } val exceptionFromFir = failedAssertions.firstOrNull { it is ExceptionFromTestError }
@@ -25,7 +25,7 @@ class FirIdenticalChecker(testServices: TestServices) : AfterAnalysisChecker(tes
} }
} }
override fun check(failedAssertions: List<AssertionError>) { override fun check(failedAssertions: List<Throwable>) {
if (failedAssertions.isNotEmpty()) return if (failedAssertions.isNotEmpty()) return
val testDataFile = testServices.moduleStructure.originalTestDataFiles.first() val testDataFile = testServices.moduleStructure.originalTestDataFiles.first()
if (testDataFile.isFirTestData) { if (testDataFile.isFirTestData) {
@@ -51,7 +51,7 @@ object JUnit5Assertions : AssertionsService() {
JUnit5PlatformAssertions.assertFalse(value, message?.invoke()) JUnit5PlatformAssertions.assertFalse(value, message?.invoke())
} }
override fun assertAll(exceptions: List<AssertionError>) { override fun assertAll(exceptions: List<Throwable>) {
exceptions.singleOrNull()?.let { throw it } exceptions.singleOrNull()?.let { throw it }
JUnit5PlatformAssertions.assertAll(exceptions.map { Executable { throw it } }) JUnit5PlatformAssertions.assertAll(exceptions.map { Executable { throw it } })
} }
@@ -40,7 +40,7 @@ object JUnit4Assertions : Assertions() {
KtUsefulTestCase.assertSameElements(message?.invoke() ?: "", expected, actual) KtUsefulTestCase.assertSameElements(message?.invoke() ?: "", expected, actual)
} }
override fun assertAll(exceptions: List<AssertionError>) { override fun assertAll(exceptions: List<Throwable>) {
exceptions.forEach { throw it } exceptions.forEach { throw it }
} }