Support dispatch infix functions
This commit is contained in:
+23
-13
@@ -24,6 +24,7 @@ import com.bnorm.power.diagram.IrTemporaryVariable
|
|||||||
import com.bnorm.power.diagram.Node
|
import com.bnorm.power.diagram.Node
|
||||||
import com.bnorm.power.diagram.SourceFile
|
import com.bnorm.power.diagram.SourceFile
|
||||||
import com.bnorm.power.diagram.buildDiagramNesting
|
import com.bnorm.power.diagram.buildDiagramNesting
|
||||||
|
import com.bnorm.power.diagram.buildDiagramNestingNullable
|
||||||
import com.bnorm.power.diagram.buildTree
|
import com.bnorm.power.diagram.buildTree
|
||||||
import com.bnorm.power.diagram.irDiagramString
|
import com.bnorm.power.diagram.irDiagramString
|
||||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||||
@@ -99,6 +100,8 @@ class PowerAssertCallTransformer(
|
|||||||
return super.visitCall(expression)
|
return super.visitCall(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val dispatchRoot =
|
||||||
|
if (expression.symbol.owner.isInfix) expression.dispatchReceiver?.let { buildTree(it) } else null
|
||||||
val extensionRoot =
|
val extensionRoot =
|
||||||
if (expression.symbol.owner.isInfix) expression.extensionReceiver?.let { buildTree(it) } else null
|
if (expression.symbol.owner.isInfix) expression.extensionReceiver?.let { buildTree(it) } else null
|
||||||
val messageArgument: IrExpression?
|
val messageArgument: IrExpression?
|
||||||
@@ -116,14 +119,21 @@ class PowerAssertCallTransformer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If all roots are null, there are no transformable parameters
|
// If all roots are null, there are no transformable parameters
|
||||||
if (extensionRoot == null && roots.all { it == null }) {
|
if (dispatchRoot == null && extensionRoot == null && roots.all { it == null }) {
|
||||||
messageCollector.info(expression, "Expression is constant and will not be power-assert transformed")
|
messageCollector.info(expression, "Expression is constant and will not be power-assert transformed")
|
||||||
return super.visitCall(expression)
|
return super.visitCall(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
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, extensionRoot)
|
return builder.diagram(
|
||||||
|
call = expression,
|
||||||
|
delegate = delegate,
|
||||||
|
messageArgument = messageArgument,
|
||||||
|
roots = roots,
|
||||||
|
dispatchRoot = dispatchRoot,
|
||||||
|
extensionRoot = extensionRoot
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DeclarationIrBuilder.diagram(
|
private fun DeclarationIrBuilder.diagram(
|
||||||
@@ -131,11 +141,13 @@ class PowerAssertCallTransformer(
|
|||||||
delegate: FunctionDelegate,
|
delegate: FunctionDelegate,
|
||||||
messageArgument: IrExpression?,
|
messageArgument: IrExpression?,
|
||||||
roots: List<Node?>,
|
roots: List<Node?>,
|
||||||
|
dispatchRoot: Node? = null,
|
||||||
extensionRoot: Node? = null
|
extensionRoot: Node? = null
|
||||||
): IrExpression {
|
): IrExpression {
|
||||||
fun recursive(
|
fun recursive(
|
||||||
index: Int,
|
index: Int,
|
||||||
extension: IrExpression? = null,
|
dispatch: IrExpression?,
|
||||||
|
extension: IrExpression?,
|
||||||
arguments: List<IrExpression?>,
|
arguments: List<IrExpression?>,
|
||||||
variables: List<IrTemporaryVariable>
|
variables: List<IrTemporaryVariable>
|
||||||
): IrExpression {
|
): IrExpression {
|
||||||
@@ -143,27 +155,25 @@ class PowerAssertCallTransformer(
|
|||||||
val prefix = buildMessagePrefix(messageArgument, delegate.messageParameter, roots, call)
|
val prefix = buildMessagePrefix(messageArgument, delegate.messageParameter, roots, call)
|
||||||
?.deepCopyWithSymbols(parent)
|
?.deepCopyWithSymbols(parent)
|
||||||
val diagram = irDiagramString(sourceFile, prefix, call, variables)
|
val diagram = irDiagramString(sourceFile, prefix, call, variables)
|
||||||
return delegate.buildCall(this, call, extension, arguments, diagram)
|
return delegate.buildCall(this, call, dispatch, extension, arguments, diagram)
|
||||||
} else {
|
} else {
|
||||||
val root = roots[index]
|
val root = roots[index]
|
||||||
if (root == null) {
|
if (root == null) {
|
||||||
val newArguments = arguments + call.getValueArgument(index)
|
val newArguments = arguments + call.getValueArgument(index)
|
||||||
return recursive(index + 1, extension, newArguments, variables)
|
return recursive(index + 1, dispatch, extension, newArguments, variables)
|
||||||
} else {
|
} else {
|
||||||
return buildDiagramNesting(root) { argument, newVariables ->
|
return buildDiagramNesting(root, variables) { argument, newVariables ->
|
||||||
val newArguments = arguments + argument
|
val newArguments = arguments + argument
|
||||||
recursive(index + 1, extension, newArguments, variables + newVariables)
|
recursive(index + 1, dispatch, extension, newArguments, newVariables)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (extensionRoot != null) {
|
return buildDiagramNestingNullable(dispatchRoot) { dispatch, newVariables ->
|
||||||
buildDiagramNesting(extensionRoot) { extension, newVariables ->
|
buildDiagramNestingNullable(extensionRoot, newVariables) { extension, newVariables ->
|
||||||
recursive(0, extension, emptyList(), newVariables)
|
recursive(0, dispatch, extension, emptyList(), newVariables)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
recursive(0, null, emptyList(), emptyList())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +226,7 @@ class PowerAssertCallTransformer(
|
|||||||
|
|
||||||
return possible.mapNotNull { overload ->
|
return possible.mapNotNull { overload ->
|
||||||
// Dispatch receivers must always match exactly
|
// Dispatch receivers must always match exactly
|
||||||
if (function.dispatchReceiverParameter != overload.owner.dispatchReceiverParameter) {
|
if (function.dispatchReceiverParameter?.type != overload.owner.dispatchReceiverParameter?.type) {
|
||||||
return@mapNotNull null
|
return@mapNotNull null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -33,6 +33,7 @@ interface FunctionDelegate {
|
|||||||
fun buildCall(
|
fun buildCall(
|
||||||
builder: IrBuilderWithScope,
|
builder: IrBuilderWithScope,
|
||||||
original: IrCall,
|
original: IrCall,
|
||||||
|
dispatchReceiver: IrExpression?,
|
||||||
extensionReceiver: IrExpression?,
|
extensionReceiver: IrExpression?,
|
||||||
valueArguments: List<IrExpression?>,
|
valueArguments: List<IrExpression?>,
|
||||||
messageArgument: IrExpression
|
messageArgument: IrExpression
|
||||||
@@ -41,12 +42,13 @@ interface FunctionDelegate {
|
|||||||
fun IrBuilderWithScope.irCallCopy(
|
fun IrBuilderWithScope.irCallCopy(
|
||||||
overload: IrSimpleFunctionSymbol,
|
overload: IrSimpleFunctionSymbol,
|
||||||
original: IrCall,
|
original: IrCall,
|
||||||
|
dispatchReceiver: IrExpression?,
|
||||||
extensionReceiver: IrExpression?,
|
extensionReceiver: IrExpression?,
|
||||||
valueArguments: List<IrExpression?>,
|
valueArguments: List<IrExpression?>,
|
||||||
messageArgument: IrExpression
|
messageArgument: IrExpression
|
||||||
): IrExpression {
|
): IrExpression {
|
||||||
return irCall(overload, type = original.type).apply {
|
return irCall(overload, type = original.type).apply {
|
||||||
dispatchReceiver = original.dispatchReceiver?.deepCopyWithSymbols(parent)
|
this.dispatchReceiver = original.dispatchReceiver?.deepCopyWithSymbols(parent)
|
||||||
this.extensionReceiver = (extensionReceiver ?: original.extensionReceiver)?.deepCopyWithSymbols(parent)
|
this.extensionReceiver = (extensionReceiver ?: original.extensionReceiver)?.deepCopyWithSymbols(parent)
|
||||||
for (i in 0 until original.typeArgumentsCount) {
|
for (i in 0 until original.typeArgumentsCount) {
|
||||||
putTypeArgument(i, original.getTypeArgument(i))
|
putTypeArgument(i, original.getTypeArgument(i))
|
||||||
|
|||||||
+9
-1
@@ -33,6 +33,7 @@ class LambdaFunctionDelegate(
|
|||||||
override fun buildCall(
|
override fun buildCall(
|
||||||
builder: IrBuilderWithScope,
|
builder: IrBuilderWithScope,
|
||||||
original: IrCall,
|
original: IrCall,
|
||||||
|
dispatchReceiver: IrExpression?,
|
||||||
extensionReceiver: IrExpression?,
|
extensionReceiver: IrExpression?,
|
||||||
valueArguments: List<IrExpression?>,
|
valueArguments: List<IrExpression?>,
|
||||||
messageArgument: IrExpression
|
messageArgument: IrExpression
|
||||||
@@ -40,6 +41,13 @@ class LambdaFunctionDelegate(
|
|||||||
val expression = irLambda(context.irBuiltIns.stringType, messageParameter.type) {
|
val expression = irLambda(context.irBuiltIns.stringType, messageParameter.type) {
|
||||||
+irReturn(messageArgument)
|
+irReturn(messageArgument)
|
||||||
}
|
}
|
||||||
irCallCopy(overload, original, extensionReceiver, valueArguments, expression)
|
irCallCopy(
|
||||||
|
overload = overload,
|
||||||
|
original = original,
|
||||||
|
dispatchReceiver = dispatchReceiver,
|
||||||
|
extensionReceiver = extensionReceiver,
|
||||||
|
valueArguments = valueArguments,
|
||||||
|
messageArgument = expression
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-3
@@ -20,11 +20,9 @@ import com.bnorm.power.irLambda
|
|||||||
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
||||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||||
import org.jetbrains.kotlin.ir.builders.irSamConversion
|
import org.jetbrains.kotlin.ir.builders.irSamConversion
|
||||||
import org.jetbrains.kotlin.ir.builders.typeOperator
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
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.expressions.IrTypeOperator
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
|
|
||||||
class SamConversionLambdaFunctionDelegate(
|
class SamConversionLambdaFunctionDelegate(
|
||||||
@@ -36,6 +34,7 @@ class SamConversionLambdaFunctionDelegate(
|
|||||||
override fun buildCall(
|
override fun buildCall(
|
||||||
builder: IrBuilderWithScope,
|
builder: IrBuilderWithScope,
|
||||||
original: IrCall,
|
original: IrCall,
|
||||||
|
dispatchReceiver: IrExpression?,
|
||||||
extensionReceiver: IrExpression?,
|
extensionReceiver: IrExpression?,
|
||||||
valueArguments: List<IrExpression?>,
|
valueArguments: List<IrExpression?>,
|
||||||
messageArgument: IrExpression
|
messageArgument: IrExpression
|
||||||
@@ -44,6 +43,13 @@ class SamConversionLambdaFunctionDelegate(
|
|||||||
+irReturn(messageArgument)
|
+irReturn(messageArgument)
|
||||||
}
|
}
|
||||||
val expression = irSamConversion(lambda, messageParameter.type)
|
val expression = irSamConversion(lambda, messageParameter.type)
|
||||||
irCallCopy(overload, original, extensionReceiver, valueArguments, expression)
|
irCallCopy(
|
||||||
|
overload = overload,
|
||||||
|
original = original,
|
||||||
|
dispatchReceiver = dispatchReceiver,
|
||||||
|
extensionReceiver = extensionReceiver,
|
||||||
|
valueArguments = valueArguments,
|
||||||
|
messageArgument = expression
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-1
@@ -31,8 +31,16 @@ class SimpleFunctionDelegate(
|
|||||||
override fun buildCall(
|
override fun buildCall(
|
||||||
builder: IrBuilderWithScope,
|
builder: IrBuilderWithScope,
|
||||||
original: IrCall,
|
original: IrCall,
|
||||||
|
dispatchReceiver: IrExpression?,
|
||||||
extensionReceiver: IrExpression?,
|
extensionReceiver: IrExpression?,
|
||||||
valueArguments: List<IrExpression?>,
|
valueArguments: List<IrExpression?>,
|
||||||
messageArgument: IrExpression
|
messageArgument: IrExpression
|
||||||
): IrExpression = builder.irCallCopy(overload, original, extensionReceiver, valueArguments, messageArgument)
|
): IrExpression = builder.irCallCopy(
|
||||||
|
overload = overload,
|
||||||
|
original = original,
|
||||||
|
dispatchReceiver = dispatchReceiver,
|
||||||
|
extensionReceiver = extensionReceiver,
|
||||||
|
valueArguments = valueArguments,
|
||||||
|
messageArgument = messageArgument
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-1
@@ -26,13 +26,22 @@ import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
|||||||
|
|
||||||
fun IrBuilderWithScope.buildDiagramNesting(
|
fun IrBuilderWithScope.buildDiagramNesting(
|
||||||
root: Node,
|
root: Node,
|
||||||
|
variables: List<IrTemporaryVariable> = emptyList(),
|
||||||
call: IrBuilderWithScope.(IrExpression, List<IrTemporaryVariable>) -> IrExpression
|
call: IrBuilderWithScope.(IrExpression, List<IrTemporaryVariable>) -> IrExpression
|
||||||
): IrExpression {
|
): IrExpression {
|
||||||
return buildExpression(root, listOf()) { argument, subStack ->
|
return buildExpression(root, variables) { argument, subStack ->
|
||||||
call(argument, subStack)
|
call(argument, subStack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.buildDiagramNestingNullable(
|
||||||
|
root: Node?,
|
||||||
|
variables: List<IrTemporaryVariable> = emptyList(),
|
||||||
|
call: IrBuilderWithScope.(IrExpression?, List<IrTemporaryVariable>) -> IrExpression
|
||||||
|
): IrExpression {
|
||||||
|
return if (root != null) buildDiagramNesting(root, variables, call) else call(null, variables)
|
||||||
|
}
|
||||||
|
|
||||||
private fun IrBuilderWithScope.buildExpression(
|
private fun IrBuilderWithScope.buildExpression(
|
||||||
node: Node,
|
node: Node,
|
||||||
variables: List<IrTemporaryVariable>,
|
variables: List<IrTemporaryVariable>,
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ import kotlin.test.fail
|
|||||||
|
|
||||||
class InfixFunctionTest {
|
class InfixFunctionTest {
|
||||||
@Test
|
@Test
|
||||||
fun `infix function call includes receiver`() {
|
fun `extension infix function call includes receiver`() {
|
||||||
val actual = execute(
|
val actual = runExtensionInfix(
|
||||||
"""
|
"""
|
||||||
(1 + 1) mustEqual (2 + 4)
|
(1 + 1) mustEqual (2 + 4)
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
@@ -44,8 +44,8 @@ class InfixFunctionTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `infix function call with constant receiver`() {
|
fun `extension infix function call with constant receiver`() {
|
||||||
val actual = execute(
|
val actual = runExtensionInfix(
|
||||||
"""
|
"""
|
||||||
1 mustEqual (2 + 4)
|
1 mustEqual (2 + 4)
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
@@ -61,8 +61,8 @@ class InfixFunctionTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `infix function call with constant parameter`() {
|
fun `extension infix function call with constant parameter`() {
|
||||||
val actual = execute(
|
val actual = runExtensionInfix(
|
||||||
"""
|
"""
|
||||||
(1 + 1) mustEqual 6
|
(1 + 1) mustEqual 6
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
@@ -78,8 +78,8 @@ class InfixFunctionTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `infix function call with only constants`() {
|
fun `extension infix function call with only constants`() {
|
||||||
val actual = execute(
|
val actual = runExtensionInfix(
|
||||||
"""
|
"""
|
||||||
2 mustEqual 6
|
2 mustEqual 6
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
@@ -93,8 +93,8 @@ class InfixFunctionTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `non-infix function call includes receiver`() {
|
fun `extension non-infix function call includes receiver`() {
|
||||||
val actual = execute(
|
val actual = runExtensionInfix(
|
||||||
"""
|
"""
|
||||||
(1 + 1).mustEqual(2 + 4)
|
(1 + 1).mustEqual(2 + 4)
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
@@ -111,8 +111,8 @@ class InfixFunctionTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `non-infix function call with constant receiver`() {
|
fun `extension non-infix function call with constant receiver`() {
|
||||||
val actual = execute(
|
val actual = runExtensionInfix(
|
||||||
"""
|
"""
|
||||||
1.mustEqual(2 + 4)
|
1.mustEqual(2 + 4)
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
@@ -128,8 +128,8 @@ class InfixFunctionTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `non-infix function call with constant parameter`() {
|
fun `extension non-infix function call with constant parameter`() {
|
||||||
val actual = execute(
|
val actual = runExtensionInfix(
|
||||||
"""
|
"""
|
||||||
(1 + 1).mustEqual(6)
|
(1 + 1).mustEqual(6)
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
@@ -145,8 +145,8 @@ class InfixFunctionTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `non-infix function call with only constants`() {
|
fun `extension non-infix function call with only constants`() {
|
||||||
val actual = execute(
|
val actual = runExtensionInfix(
|
||||||
"""
|
"""
|
||||||
2.mustEqual(6)
|
2.mustEqual(6)
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
@@ -159,24 +159,199 @@ class InfixFunctionTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun execute(mainBody: String): String {
|
@Test
|
||||||
val file = SourceFile.kotlin(
|
fun `dispatch infix function call includes receiver`() {
|
||||||
name = "main.kt",
|
val actual = runDispatchInfix(
|
||||||
contents = """
|
"""
|
||||||
infix fun <V> V.mustEqual(expected: V): Unit = assert(this == expected)
|
Wrapper(1 + 1) mustEqual (2 + 4)
|
||||||
|
""".trimIndent()
|
||||||
fun <V> V.mustEqual(expected: V, message: () -> String): Unit =
|
|
||||||
assert(this == expected, message)
|
|
||||||
|
|
||||||
fun main() {
|
|
||||||
$mainBody
|
|
||||||
}
|
|
||||||
""",
|
|
||||||
trimIndent = false
|
|
||||||
)
|
)
|
||||||
|
assertEquals(
|
||||||
|
"""
|
||||||
|
Wrapper(1 + 1) mustEqual (2 + 4)
|
||||||
|
| | |
|
||||||
|
| | 6
|
||||||
|
| 2
|
||||||
|
Wrapper
|
||||||
|
""".trimIndent(),
|
||||||
|
actual.trim()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
val result = compile(listOf(file), PowerAssertComponentRegistrar(setOf(FqName("mustEqual"))))
|
@Test
|
||||||
assertEquals(KotlinCompilation.ExitCode.OK, result.exitCode)
|
fun `dispatch infix function call with constant receiver`() {
|
||||||
|
val actual = runDispatchInfix(
|
||||||
|
"""
|
||||||
|
Wrapper(1) mustEqual (2 + 4)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
"""
|
||||||
|
Wrapper(1) mustEqual (2 + 4)
|
||||||
|
| |
|
||||||
|
| 6
|
||||||
|
Wrapper
|
||||||
|
""".trimIndent(),
|
||||||
|
actual.trim()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `dispatch infix function call with constant parameter`() {
|
||||||
|
val actual = runDispatchInfix(
|
||||||
|
"""
|
||||||
|
Wrapper(1 + 1) mustEqual 6
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
"""
|
||||||
|
Wrapper(1 + 1) mustEqual 6
|
||||||
|
| |
|
||||||
|
| 2
|
||||||
|
Wrapper
|
||||||
|
""".trimIndent(),
|
||||||
|
actual.trim()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `dispatch infix function call with only constants`() {
|
||||||
|
val actual = runDispatchInfix(
|
||||||
|
"""
|
||||||
|
Wrapper(2) mustEqual 6
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
"""
|
||||||
|
Wrapper(2) mustEqual 6
|
||||||
|
|
|
||||||
|
Wrapper
|
||||||
|
""".trimIndent(),
|
||||||
|
actual.trim()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `dispatch non-infix function call includes receiver`() {
|
||||||
|
val actual = runDispatchInfix(
|
||||||
|
"""
|
||||||
|
Wrapper(1 + 1).mustEqual(2 + 4)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
"""
|
||||||
|
Wrapper(1 + 1).mustEqual(2 + 4)
|
||||||
|
| | |
|
||||||
|
| | 6
|
||||||
|
| 2
|
||||||
|
Wrapper
|
||||||
|
""".trimIndent(),
|
||||||
|
actual.trim()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `dispatch non-infix function call with constant receiver`() {
|
||||||
|
val actual = runDispatchInfix(
|
||||||
|
"""
|
||||||
|
Wrapper(1).mustEqual(2 + 4)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
"""
|
||||||
|
Wrapper(1).mustEqual(2 + 4)
|
||||||
|
| |
|
||||||
|
| 6
|
||||||
|
Wrapper
|
||||||
|
""".trimIndent(),
|
||||||
|
actual.trim()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `dispatch non-infix function call with constant parameter`() {
|
||||||
|
val actual = runDispatchInfix(
|
||||||
|
"""
|
||||||
|
Wrapper(1 + 1).mustEqual(6)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
"""
|
||||||
|
Wrapper(1 + 1).mustEqual(6)
|
||||||
|
| |
|
||||||
|
| 2
|
||||||
|
Wrapper
|
||||||
|
""".trimIndent(),
|
||||||
|
actual.trim()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `dispatch non-infix function call with only constants`() {
|
||||||
|
val actual = runDispatchInfix(
|
||||||
|
"""
|
||||||
|
Wrapper(2).mustEqual(6)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
"""
|
||||||
|
Wrapper(2).mustEqual(6)
|
||||||
|
|
|
||||||
|
Wrapper
|
||||||
|
""".trimIndent(),
|
||||||
|
actual.trim()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun runExtensionInfix(mainBody: String): String {
|
||||||
|
return run(
|
||||||
|
SourceFile.kotlin(
|
||||||
|
name = "main.kt",
|
||||||
|
contents = """
|
||||||
|
infix fun <V> V.mustEqual(expected: V): Unit = assert(this == expected)
|
||||||
|
|
||||||
|
fun <V> V.mustEqual(expected: V, message: () -> String): Unit =
|
||||||
|
assert(this == expected, message)
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
$mainBody
|
||||||
|
}
|
||||||
|
""".trimIndent(),
|
||||||
|
trimIndent = false
|
||||||
|
),
|
||||||
|
setOf(FqName("mustEqual"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun runDispatchInfix(mainBody: String): String {
|
||||||
|
return run(
|
||||||
|
SourceFile.kotlin(
|
||||||
|
name = "main.kt",
|
||||||
|
contents = """
|
||||||
|
class Wrapper<V>(
|
||||||
|
private val value: V
|
||||||
|
) {
|
||||||
|
infix fun mustEqual(expected: V): Unit = assert(value == expected)
|
||||||
|
|
||||||
|
fun mustEqual(expected: V, message: () -> String): Unit =
|
||||||
|
assert(value == expected, message)
|
||||||
|
|
||||||
|
override fun toString() = "Wrapper"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
$mainBody
|
||||||
|
}
|
||||||
|
""".trimIndent(),
|
||||||
|
trimIndent = false
|
||||||
|
),
|
||||||
|
setOf(FqName("Wrapper.mustEqual"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun run(file: SourceFile, fqNames: Set<FqName>): String {
|
||||||
|
val result = compile(listOf(file), PowerAssertComponentRegistrar(fqNames))
|
||||||
|
assertEquals(KotlinCompilation.ExitCode.OK, result.exitCode, "Failed with messages: " + result.messages)
|
||||||
|
|
||||||
val kClazz = result.classLoader.loadClass("MainKt")
|
val kClazz = result.classLoader.loadClass("MainKt")
|
||||||
val main = kClazz.declaredMethods.single { it.name == "main" && it.parameterCount == 0 }
|
val main = kClazz.declaredMethods.single { it.name == "main" && it.parameterCount == 0 }
|
||||||
|
|||||||
Reference in New Issue
Block a user