Merge pull request #53 from bnorm/junit5

Support JVM static functions
This commit is contained in:
Brian Norman
2022-03-13 12:16:17 -05:00
committed by GitHub
18 changed files with 566 additions and 134 deletions
+7
View File
@@ -1,9 +1,16 @@
root = true root = true
[*] [*]
charset = utf-8
end_of_line = lf end_of_line = lf
insert_final_newline = true insert_final_newline = true
[*.{kt,kts}] [*.{kt,kts}]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2
ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL
ij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,^
ij_kotlin_name_count_to_use_star_import = 2147483647
ij_kotlin_name_count_to_use_star_import_for_members = 2147483647
ij_kotlin_packages_to_use_import_on_demand = unset
+5 -1
View File
@@ -15,7 +15,7 @@ dependencies {
kapt("com.google.auto.service:auto-service:1.0.1") kapt("com.google.auto.service:auto-service:1.0.1")
compileOnly("com.google.auto.service:auto-service-annotations:1.0.1") compileOnly("com.google.auto.service:auto-service-annotations:1.0.1")
testImplementation(kotlin("test-junit")) testImplementation(kotlin("test-junit5"))
testImplementation("org.jetbrains.kotlin:kotlin-compiler-embeddable") testImplementation("org.jetbrains.kotlin:kotlin-compiler-embeddable")
testImplementation("com.github.tschuchortdev:kotlin-compile-testing:1.4.6") testImplementation("com.github.tschuchortdev:kotlin-compile-testing:1.4.6")
} }
@@ -24,6 +24,10 @@ tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8" kotlinOptions.jvmTarget = "1.8"
} }
tasks.withType<Test> {
useJUnitPlatform()
}
tasks.dokka { tasks.dokka {
outputFormat = "html" outputFormat = "html"
outputDirectory = "$buildDir/javadoc" outputDirectory = "$buildDir/javadoc"
@@ -18,6 +18,7 @@ package com.bnorm.power
import com.bnorm.power.delegate.FunctionDelegate import com.bnorm.power.delegate.FunctionDelegate
import com.bnorm.power.delegate.LambdaFunctionDelegate import com.bnorm.power.delegate.LambdaFunctionDelegate
import com.bnorm.power.delegate.SamConversionLambdaFunctionDelegate
import com.bnorm.power.delegate.SimpleFunctionDelegate import com.bnorm.power.delegate.SimpleFunctionDelegate
import com.bnorm.power.diagram.IrTemporaryVariable import com.bnorm.power.diagram.IrTemporaryVariable
import com.bnorm.power.diagram.Node import com.bnorm.power.diagram.Node
@@ -26,40 +27,44 @@ import com.bnorm.power.diagram.buildTree
import com.bnorm.power.diagram.info import com.bnorm.power.diagram.info
import com.bnorm.power.diagram.irDiagramString import com.bnorm.power.diagram.irDiagramString
import com.bnorm.power.diagram.substring import com.bnorm.power.diagram.substring
import com.bnorm.power.internal.ReturnableBlockTransformer
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.ir.asInlinable
import org.jetbrains.kotlin.backend.common.ir.inline
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.backend.js.utils.asString import org.jetbrains.kotlin.ir.backend.js.utils.asString
import org.jetbrains.kotlin.ir.builders.irBlock import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irString import org.jetbrains.kotlin.ir.builders.irString
import org.jetbrains.kotlin.ir.builders.parent import org.jetbrains.kotlin.ir.builders.parent
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.declarations.path import org.jetbrains.kotlin.ir.declarations.path
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.IrTypeArgument import org.jetbrains.kotlin.ir.types.IrTypeArgument
import org.jetbrains.kotlin.ir.types.IrTypeProjection import org.jetbrains.kotlin.ir.types.IrTypeProjection
import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.isBoolean import org.jetbrains.kotlin.ir.types.isBoolean
import org.jetbrains.kotlin.ir.types.isSubtypeOf import org.jetbrains.kotlin.ir.types.isSubtypeOf
import org.jetbrains.kotlin.ir.types.isSubtypeOfClass
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.ir.util.isFunctionOrKFunction import org.jetbrains.kotlin.ir.util.isFunctionOrKFunction
import org.jetbrains.kotlin.ir.util.kotlinFqName import org.jetbrains.kotlin.ir.util.kotlinFqName
import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.ir.util.parentClassOrNull
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
class PowerAssertCallTransformer( class PowerAssertCallTransformer(
@@ -122,10 +127,6 @@ class PowerAssertCallTransformer(
val symbol = currentScope!!.scope.scopeOwnerSymbol val symbol = currentScope!!.scope.scopeOwnerSymbol
val builder = DeclarationIrBuilder(context, symbol, expression.startOffset, expression.endOffset) val builder = DeclarationIrBuilder(context, symbol, expression.startOffset, expression.endOffset)
return builder.diagram(expression, delegate, messageArgument, roots) return builder.diagram(expression, delegate, messageArgument, roots)
// .also { println(expression.dump()) }
// .also { println(it.dump()) }
// .also { println(expression.dumpKotlinLike()) }
// .also { println(it.dumpKotlinLike()) }
} }
private fun DeclarationIrBuilder.diagram( private fun DeclarationIrBuilder.diagram(
@@ -138,7 +139,8 @@ class PowerAssertCallTransformer(
variables: List<IrTemporaryVariable> = listOf() variables: List<IrTemporaryVariable> = listOf()
): IrExpression { ): IrExpression {
if (index >= roots.size) { if (index >= roots.size) {
val prefix = buildMessagePrefix(messageArgument, roots, original)?.deepCopyWithSymbols(parent) val prefix = buildMessagePrefix(messageArgument, delegate.messageParameter, roots, original)
?.deepCopyWithSymbols(parent)
val diagram = irDiagramString(file, fileSource, prefix, original, variables) val diagram = irDiagramString(file, fileSource, prefix, original, variables)
return delegate.buildCall(this, original, arguments, diagram) return delegate.buildCall(this, original, arguments, diagram)
} else { } else {
@@ -157,18 +159,30 @@ class PowerAssertCallTransformer(
private fun DeclarationIrBuilder.buildMessagePrefix( private fun DeclarationIrBuilder.buildMessagePrefix(
messageArgument: IrExpression?, messageArgument: IrExpression?,
messageParameter: IrValueParameter,
roots: List<Node?>, roots: List<Node?>,
original: IrCall original: IrCall
): IrExpression? { ): IrExpression? {
return when { return when {
messageArgument is IrConst<*> -> messageArgument messageArgument is IrConst<*> -> messageArgument
messageArgument is IrStringConcatenation -> messageArgument messageArgument is IrStringConcatenation -> messageArgument
messageArgument != null -> irBlock { messageArgument is IrGetValue -> {
+messageArgument.deepCopyWithSymbols(parent) if (messageArgument.type.isAssignableTo(context.irBuiltIns.stringType)) {
.asInlinable(this) return messageArgument
.inline(parent) } else {
.patchDeclarationParents(scope.getLocalDeclarationParent()) val invoke = messageParameter.type.classOrNull!!.functions
}.transform(ReturnableBlockTransformer(context, scope.scopeOwnerSymbol), null) .filter { !it.owner.isFakeOverride } // TODO best way to find single access method?
.single()
irCall(invoke).apply { dispatchReceiver = messageArgument }
}
}
// Kotlin Lambda or SAMs conversion lambda
messageArgument is IrFunctionExpression || messageArgument is IrTypeOperatorCall -> {
val invoke = messageParameter.type.classOrNull!!.functions
.filter { !it.owner.isFakeOverride } // TODO best way to find single access method?
.single()
irCall(invoke).apply { dispatchReceiver = messageArgument }
}
// TODO what should the default message be? // TODO what should the default message be?
roots.size == 1 && original.getValueArgument(0)!!.type.isBoolean() -> irString("Assertion failed") roots.size == 1 && original.getValueArgument(0)!!.type.isBoolean() -> irString("Assertion failed")
else -> null else -> null
@@ -179,7 +193,18 @@ class PowerAssertCallTransformer(
val values = function.valueParameters val values = function.valueParameters
if (values.isEmpty()) return emptyList() if (values.isEmpty()) return emptyList()
return context.referenceFunctions(function.kotlinFqName) // Java static functions require searching by class
val parentClassFunctions = (
function.parentClassOrNull
?.let { context.referenceClass(it.kotlinFqName) }
?.functions ?: emptySequence()
)
.filter { it.owner.kotlinFqName == function.kotlinFqName }
.toList()
val possible = (context.referenceFunctions(function.kotlinFqName) + parentClassFunctions)
.distinct()
return possible
.mapNotNull { overload -> .mapNotNull { overload ->
val parameters = overload.owner.valueParameters val parameters = overload.owner.valueParameters
if (parameters.size !in values.size..values.size + 1) return@mapNotNull null if (parameters.size !in values.size..values.size + 1) return@mapNotNull null
@@ -189,8 +214,10 @@ class PowerAssertCallTransformer(
val messageParameter = parameters.last() val messageParameter = parameters.last()
return@mapNotNull when { return@mapNotNull when {
isStringSupertype(messageParameter.type) -> SimpleFunctionDelegate(overload) isStringSupertype(messageParameter.type) -> SimpleFunctionDelegate(overload, messageParameter)
isStringFunction(messageParameter.type) -> LambdaFunctionDelegate(overload, messageParameter) isStringFunction(messageParameter.type) -> LambdaFunctionDelegate(overload, messageParameter)
isStringJavaSupplierFunction(messageParameter.type) ->
SamConversionLambdaFunctionDelegate(overload, messageParameter)
else -> null else -> null
} }
} }
@@ -199,6 +226,12 @@ class PowerAssertCallTransformer(
private fun isStringFunction(type: IrType): Boolean = private fun isStringFunction(type: IrType): Boolean =
type.isFunctionOrKFunction() && type is IrSimpleType && (type.arguments.size == 1 && isStringSupertype(type.arguments.first())) type.isFunctionOrKFunction() && type is IrSimpleType && (type.arguments.size == 1 && isStringSupertype(type.arguments.first()))
private fun isStringJavaSupplierFunction(type: IrType): Boolean {
val javaSupplier = context.referenceClass(FqName("java.util.function.Supplier"))
return javaSupplier != null && type.isSubtypeOfClass(javaSupplier) &&
type is IrSimpleType && (type.arguments.size == 1 && isStringSupertype(type.arguments.first()))
}
private fun isStringSupertype(argument: IrTypeArgument): Boolean = private fun isStringSupertype(argument: IrTypeArgument): Boolean =
argument is IrTypeProjection && isStringSupertype(argument.type) argument is IrTypeProjection && isStringSupertype(argument.type)
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.parent import org.jetbrains.kotlin.ir.builders.parent
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
@@ -27,6 +28,7 @@ import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
interface FunctionDelegate { interface FunctionDelegate {
val function: IrFunction val function: IrFunction
val messageParameter: IrValueParameter
fun buildCall( fun buildCall(
builder: IrBuilderWithScope, builder: IrBuilderWithScope,
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
class LambdaFunctionDelegate( class LambdaFunctionDelegate(
private val overload: IrSimpleFunctionSymbol, private val overload: IrSimpleFunctionSymbol,
private val messageParameter: IrValueParameter override val messageParameter: IrValueParameter,
) : FunctionDelegate { ) : FunctionDelegate {
override val function = overload.owner override val function = overload.owner
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2021 Brian Norman
*
* 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.
*/
package com.bnorm.power.delegate
import com.bnorm.power.irLambda
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.builders.typeOperator
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
class SamConversionLambdaFunctionDelegate(
private val overload: IrSimpleFunctionSymbol,
override val messageParameter: IrValueParameter,
) : FunctionDelegate {
override val function = overload.owner
override fun buildCall(
builder: IrBuilderWithScope,
original: IrCall,
arguments: List<IrExpression?>,
message: IrExpression
): IrExpression = with(builder) {
val lambda = irLambda(context.irBuiltIns.stringType, messageParameter.type) {
+irReturn(message)
}
val expression = typeOperator(messageParameter.type, lambda, IrTypeOperator.SAM_CONVERSION, messageParameter.type)
irCallCopy(overload, original, arguments, expression)
}
}
@@ -17,12 +17,14 @@
package com.bnorm.power.delegate package com.bnorm.power.delegate
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
class SimpleFunctionDelegate( class SimpleFunctionDelegate(
private val overload: IrSimpleFunctionSymbol private val overload: IrSimpleFunctionSymbol,
override val messageParameter: IrValueParameter,
) : FunctionDelegate { ) : FunctionDelegate {
override val function = overload.owner override val function = overload.owner
@@ -1,98 +0,0 @@
/*
* Copyright 2010-2018 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.
*
* Copied from https://github.com/JetBrains/kotlin/blob/1.4.20/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ReturnableBlockLowering.kt
*/
package com.bnorm.power.internal
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irComposite
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.transformStatement
// TODO Remove when inlining works correctly on Kotlin/JS and Kotlin/Native
class ReturnableBlockTransformer(val context: IrGeneratorContext, val containerSymbol: IrSymbol? = null) : IrElementTransformerVoidWithContext() {
private var labelCnt = 0
private val returnMap = mutableMapOf<IrReturnableBlockSymbol, (IrReturn) -> IrExpression>()
override fun visitReturn(expression: IrReturn): IrExpression {
expression.transformChildrenVoid()
return returnMap[expression.returnTargetSymbol]?.invoke(expression) ?: expression
}
override fun visitContainerExpression(expression: IrContainerExpression): IrExpression {
if (expression !is IrReturnableBlock) return super.visitContainerExpression(expression)
val scopeSymbol = currentScope?.scope?.scopeOwnerSymbol ?: containerSymbol
val builder = DeclarationIrBuilder(context, scopeSymbol!!)
val variable by lazy {
builder.scope.createTmpVariable(expression.type, "tmp\$ret\$${labelCnt++}", true)
}
val loop by lazy {
IrDoWhileLoopImpl(
expression.startOffset,
expression.endOffset,
context.irBuiltIns.unitType,
expression.origin
).apply {
label = "l\$ret\$${labelCnt++}"
condition = builder.irBoolean(false)
}
}
var hasReturned = false
returnMap[expression.symbol] = { returnExpression ->
hasReturned = true
builder.irComposite(returnExpression) {
+irSet(variable.symbol, returnExpression.value)
+irBreak(loop)
}
}
val newStatements = expression.statements.mapIndexed { i, s ->
if (i == expression.statements.lastIndex && s is IrReturn && s.returnTargetSymbol == expression.symbol) {
s.transformChildrenVoid()
if (!hasReturned) s.value else {
builder.irSet(variable.symbol, s.value)
}
} else {
s.transformStatement(this)
}
}
returnMap.remove(expression.symbol)
if (!hasReturned) {
return IrCompositeImpl(
expression.startOffset,
expression.endOffset,
expression.type,
expression.origin,
newStatements
)
} else {
loop.body = IrBlockImpl(
expression.startOffset,
expression.endOffset,
context.irBuiltIns.unitType,
expression.origin,
newStatements
)
return builder.irComposite(expression, expression.origin) {
+variable
+loop
+irGet(variable)
}
}
}
}
@@ -16,7 +16,7 @@
package com.bnorm.power package com.bnorm.power
import org.junit.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
class ArithmeticExpressionTest { class ArithmeticExpressionTest {
@@ -17,9 +17,9 @@
package com.bnorm.power package com.bnorm.power
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.junit.Test import kotlin.test.Test
class CompilerTest { class AssertTest {
@Test @Test
fun memberFunctions() { fun memberFunctions() {
assertMessage( assertMessage(
@@ -77,6 +77,23 @@ assert(1 == 2) { "Not equal" }
) )
} }
@Test
fun customLocalVariableMessage() {
assertMessage(
"""
fun main() {
val lambda = { "Not equal" }
assert(1 == 2, lambda)
}""",
"""
Not equal
assert(1 == 2, lambda)
|
false
""".trimIndent()
)
}
@Test @Test
fun booleanExpressionsShortCircuit() { fun booleanExpressionsShortCircuit() {
assertMessage( assertMessage(
@@ -19,10 +19,10 @@ package com.bnorm.power
import com.tschuchort.compiletesting.KotlinCompilation import com.tschuchort.compiletesting.KotlinCompilation
import com.tschuchort.compiletesting.SourceFile import com.tschuchort.compiletesting.SourceFile
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.junit.Test
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.PrintStream import java.io.PrintStream
import java.lang.reflect.InvocationTargetException import java.lang.reflect.InvocationTargetException
import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
class DebugFunctionTest { class DebugFunctionTest {
@@ -0,0 +1,330 @@
/*
* Copyright (C) 2021 Brian Norman
*
* 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.
*/
package com.bnorm.power
import org.jetbrains.kotlin.name.FqName
import kotlin.test.Test
class Junit5AssertionsTest {
@Test
fun `test JUnit5 Assertions#assertTrue transformation`() {
assertMessage(
"""
import org.junit.jupiter.api.Assertions.assertTrue
fun main() {
assertTrue(1 != 1)
}""",
"""
Assertion failed
assertTrue(1 != 1)
|
false ==> expected: <true> but was: <false>
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("org.junit.jupiter.api.Assertions.assertTrue")))
)
}
@Test
fun `test JUnit5 Assertions#assertTrue transformation with message`() {
assertMessage(
"""
import org.junit.jupiter.api.Assertions.assertTrue
fun main() {
assertTrue(1 != 1, "Message:")
}""",
"""
Message:
assertTrue(1 != 1, "Message:")
|
false ==> expected: <true> but was: <false>
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("org.junit.jupiter.api.Assertions.assertTrue")))
)
}
@Test
fun `test JUnit5 Assertions#assertTrue transformation with local variable message`() {
assertMessage(
"""
import org.junit.jupiter.api.Assertions.assertTrue
fun main() {
val message = "Message:"
assertTrue(1 != 1, message)
}""",
"""
Message:
assertTrue(1 != 1, message)
|
false ==> expected: <true> but was: <false>
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("org.junit.jupiter.api.Assertions.assertTrue")))
)
}
@Test
fun `test JUnit5 Assertions#assertTrue transformation with message supplier`() {
assertMessage(
"""
import org.junit.jupiter.api.Assertions.assertTrue
fun main() {
assertTrue(1 != 1) { "Message:" }
}""",
"""
Message:
assertTrue(1 != 1) { "Message:" }
|
false ==> expected: <true> but was: <false>
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("org.junit.jupiter.api.Assertions.assertTrue")))
)
}
@Test
fun `test JUnit5 Assertions#assertTrue transformation with local variable message supplier`() {
assertMessage(
"""
import java.util.function.Supplier
import org.junit.jupiter.api.Assertions.assertTrue
fun main() {
val supplier = Supplier { "Message:" }
assertTrue(1 != 1, supplier)
}""",
"""
Message:
assertTrue(1 != 1, supplier)
|
false ==> expected: <true> but was: <false>
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("org.junit.jupiter.api.Assertions.assertTrue")))
)
}
@Test
fun `test JUnit5 Assertions#assertFalse transformation`() {
assertMessage(
"""
import org.junit.jupiter.api.Assertions.assertFalse
fun main() {
assertFalse(1 == 1)
}""",
"""
Assertion failed
assertFalse(1 == 1)
|
true ==> expected: <false> but was: <true>
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("org.junit.jupiter.api.Assertions.assertFalse")))
)
}
@Test
fun `test JUnit5 Assertions#assertFalse transformation with message`() {
assertMessage(
"""
import org.junit.jupiter.api.Assertions.assertFalse
fun main() {
assertFalse(1 == 1, "Message:")
}""",
"""
Message:
assertFalse(1 == 1, "Message:")
|
true ==> expected: <false> but was: <true>
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("org.junit.jupiter.api.Assertions.assertFalse")))
)
}
@Test
fun `test JUnit5 Assertions#assertFalse transformation with local variable message`() {
assertMessage(
"""
import org.junit.jupiter.api.Assertions.assertFalse
fun main() {
val message = "Message:"
assertFalse(1 == 1, message)
}""",
"""
Message:
assertFalse(1 == 1, message)
|
true ==> expected: <false> but was: <true>
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("org.junit.jupiter.api.Assertions.assertFalse")))
)
}
@Test
fun `test JUnit5 Assertions#assertFalse transformation with message supplier`() {
assertMessage(
"""
import org.junit.jupiter.api.Assertions.assertFalse
fun main() {
assertFalse(1 == 1) { "Message:" }
}""",
"""
Message:
assertFalse(1 == 1) { "Message:" }
|
true ==> expected: <false> but was: <true>
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("org.junit.jupiter.api.Assertions.assertFalse")))
)
}
@Test
fun `test JUnit5 Assertions#assertFalse transformation with local variable message supplier`() {
assertMessage(
"""
import java.util.function.Supplier
import org.junit.jupiter.api.Assertions.assertFalse
fun main() {
val supplier = Supplier { "Message:" }
assertFalse(1 == 1, supplier)
}""",
"""
Message:
assertFalse(1 == 1, supplier)
|
true ==> expected: <false> but was: <true>
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("org.junit.jupiter.api.Assertions.assertFalse")))
)
}
@Test
fun `test JUnit5 Assertions#assertEquals transformation`() {
assertMessage(
"""
import org.junit.jupiter.api.Assertions.assertEquals
fun main() {
val greeting = "Hello"
val name = "World"
assertEquals(greeting, name)
}""",
"""
assertEquals(greeting, name)
| |
| World
Hello ==> expected: <Hello> but was: <World>
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("org.junit.jupiter.api.Assertions.assertEquals")))
)
}
@Test
fun `test JUnit5 Assertions#assertEquals transformation with message`() {
assertMessage(
"""
import org.junit.jupiter.api.Assertions.assertEquals
fun main() {
val greeting = "Hello"
val name = "World"
assertEquals(greeting, name, "Message:")
}""",
"""
Message:
assertEquals(greeting, name, "Message:")
| |
| World
Hello ==> expected: <Hello> but was: <World>
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("org.junit.jupiter.api.Assertions.assertEquals")))
)
}
@Test
fun `test JUnit5 Assertions#assertEquals transformation with local variable message`() {
assertMessage(
"""
import org.junit.jupiter.api.Assertions.assertEquals
fun main() {
val greeting = "Hello"
val name = "World"
val message = "Message:"
assertEquals(greeting, name, message)
}""",
"""
Message:
assertEquals(greeting, name, message)
| |
| World
Hello ==> expected: <Hello> but was: <World>
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("org.junit.jupiter.api.Assertions.assertEquals")))
)
}
@Test
fun `test JUnit5 Assertions#assertEquals transformation with message supplier`() {
assertMessage(
"""
import org.junit.jupiter.api.Assertions.assertEquals
fun main() {
val greeting = "Hello"
val name = "World"
assertEquals(greeting, name) { "Message:" }
}""",
"""
Message:
assertEquals(greeting, name) { "Message:" }
| |
| World
Hello ==> expected: <Hello> but was: <World>
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("org.junit.jupiter.api.Assertions.assertEquals")))
)
}
@Test
fun `test JUnit5 Assertions#assertEquals transformation with local variable message supplier`() {
assertMessage(
"""
import java.util.function.Supplier
import org.junit.jupiter.api.Assertions.assertEquals
fun main() {
val greeting = "Hello"
val name = "World"
val supplier = Supplier { "Message:" }
assertEquals(greeting, name, supplier)
}""",
"""
Message:
assertEquals(greeting, name, supplier)
| |
| World
Hello ==> expected: <Hello> but was: <World>
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("org.junit.jupiter.api.Assertions.assertEquals")))
)
}
}
@@ -17,9 +17,9 @@
package com.bnorm.power package com.bnorm.power
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.junit.Test import kotlin.test.Test
class AssertLibraryTest { class KotlinTestAssertTest {
@Test @Test
fun `test assertTrue transformation`() { fun `test assertTrue transformation`() {
assertMessage( assertMessage(
@@ -58,6 +58,26 @@ class AssertLibraryTest {
) )
} }
@Test
fun `test assertTrue transformation with local variable message`() {
assertMessage(
"""
import kotlin.test.assertTrue
fun main() {
val message = "Message:"
assertTrue(1 != 1, message)
}""",
"""
Message:
assertTrue(1 != 1, message)
|
false
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertTrue")))
)
}
@Test @Test
fun `test assertFalse transformation`() { fun `test assertFalse transformation`() {
assertMessage( assertMessage(
@@ -96,6 +116,26 @@ class AssertLibraryTest {
) )
} }
@Test
fun `test assertFalse transformation with local variable message`() {
assertMessage(
"""
import kotlin.test.assertFalse
fun main() {
val message = "Message:"
assertFalse(1 == 1, message)
}""",
"""
Message:
assertFalse(1 == 1, message)
|
true
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertFalse")))
)
}
@Test @Test
fun `test assertEquals transformation`() { fun `test assertEquals transformation`() {
assertMessage( assertMessage(
@@ -111,7 +151,7 @@ class AssertLibraryTest {
assertEquals(greeting, name) assertEquals(greeting, name)
| | | |
| World | World
Hello expected:<[Hello]> but was:<[World]> Hello ==> expected: <Hello> but was: <World>
""".trimIndent(), """.trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertEquals"))) PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertEquals")))
) )
@@ -133,7 +173,30 @@ class AssertLibraryTest {
assertEquals(greeting, name, "Message:") assertEquals(greeting, name, "Message:")
| | | |
| World | World
Hello expected:<[Hello]> but was:<[World]> Hello ==> expected: <Hello> but was: <World>
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertEquals")))
)
}
@Test
fun `test assertEquals transformation with local variable message`() {
assertMessage(
"""
import kotlin.test.assertEquals
fun main() {
val greeting = "Hello"
val name = "World"
val message = "Message:"
assertEquals(greeting, name, message)
}""",
"""
Message:
assertEquals(greeting, name, message)
| |
| World
Hello ==> expected: <Hello> but was: <World>
""".trimIndent(), """.trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertEquals"))) PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertEquals")))
) )
@@ -152,7 +215,7 @@ class AssertLibraryTest {
""" """
assertNotNull(name) assertNotNull(name)
| |
null null ==> expected: not <null>
""".trimIndent(), """.trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertNotNull"))) PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertNotNull")))
) )
@@ -172,7 +235,28 @@ class AssertLibraryTest {
Message: Message:
assertNotNull(name, "Message:") assertNotNull(name, "Message:")
| |
null null ==> expected: not <null>
""".trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertNotNull")))
)
}
@Test
fun `test assertNotNull transformation with local variable message`() {
assertMessage(
"""
import kotlin.test.assertNotNull
fun main() {
val name: String? = null
val message = "Message:"
assertNotNull(name, message)
}""",
"""
Message:
assertNotNull(name, message)
|
null ==> expected: not <null>
""".trimIndent(), """.trimIndent(),
PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertNotNull"))) PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertNotNull")))
) )
@@ -17,7 +17,7 @@
package com.bnorm.power package com.bnorm.power
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.junit.Test import kotlin.test.Test
class LamdaTest { class LamdaTest {
@Test @Test
@@ -19,10 +19,10 @@ package com.bnorm.power
import com.tschuchort.compiletesting.KotlinCompilation import com.tschuchort.compiletesting.KotlinCompilation
import com.tschuchort.compiletesting.SourceFile import com.tschuchort.compiletesting.SourceFile
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.junit.Test
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.PrintStream import java.io.PrintStream
import java.lang.reflect.InvocationTargetException import java.lang.reflect.InvocationTargetException
import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
class MultiParameterFunctionTest { class MultiParameterFunctionTest {
@@ -16,7 +16,7 @@
package com.bnorm.power package com.bnorm.power
import org.junit.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
class RegexMatchTest { class RegexMatchTest {
@@ -62,7 +62,7 @@ fun executeAssertion(
} }
fail("should have thrown assertion") fail("should have thrown assertion")
} catch (t: Throwable) { } catch (t: Throwable) {
return t.message!! return t.message ?: ""
} }
} }
+5 -1
View File
@@ -32,7 +32,7 @@ kotlin {
} }
val jvmTest by getting { val jvmTest by getting {
dependencies { dependencies {
implementation(kotlin("test-junit")) implementation(kotlin("test-junit5"))
} }
} }
val jsTest by getting { val jsTest by getting {
@@ -49,6 +49,10 @@ kotlin {
} }
} }
tasks.withType<Test> {
useJUnitPlatform()
}
configure<com.bnorm.power.PowerAssertGradleExtension> { configure<com.bnorm.power.PowerAssertGradleExtension> {
functions = listOf( functions = listOf(
"kotlin.assert", "kotlin.assert",