[JS] Support custom Promise declarations for kotlin.test @AfterTest

^KT-63359 fixed


Merge-request: KT-MR-14001
Merged-by: Anton Bannykh <Anton.Bannykh@jetbrains.com>
This commit is contained in:
Anton Bannykh
2024-01-24 12:43:51 +00:00
committed by Space Team
parent 9a74a5fcdd
commit 245409dede
3 changed files with 45 additions and 17 deletions
@@ -14,19 +14,26 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.utils.getJsModule
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irString
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
import org.jetbrains.kotlin.ir.expressions.IrDynamicOperator
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrDynamicMemberExpressionImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrDynamicOperatorExpressionImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext.asSimpleType
import org.jetbrains.kotlin.utils.filterIsInstanceAnd
import org.jetbrains.kotlin.utils.findIsInstanceAnd
import org.jetbrains.kotlin.utils.memoryOptimizedMap
@@ -65,7 +72,7 @@ class TestGenerator(val context: JsCommonBackendContext, val groupByPackage: Boo
private fun IrSimpleFunctionSymbol.createInvocation(
name: String,
parentFunction: IrSimpleFunction,
ignored: Boolean = false
ignored: Boolean = false,
): IrSimpleFunction {
val body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET, emptyList())
@@ -134,7 +141,7 @@ class TestGenerator(val context: JsCommonBackendContext, val groupByPackage: Boo
beforeFuns: List<IrSimpleFunction>,
afterFuns: List<IrSimpleFunction>,
irClass: IrClass,
parentFunction: IrSimpleFunction
parentFunction: IrSimpleFunction,
) {
val fn = context.testFun!!.createInvocation(testFun.name.asString(), parentFunction, testFun.isIgnored)
val body = fn.body as IrBlockBody
@@ -179,10 +186,8 @@ class TestGenerator(val context: JsCommonBackendContext, val groupByPackage: Boo
return
}
if (context is JsIrBackendContext && (testFun.returnType as? IrSimpleType)?.classifier == context.intrinsics.promiseClassSymbol) {
val finally = context.intrinsics.promiseClassSymbol.owner.declarations
.findIsInstanceAnd<IrSimpleFunction> { it.name.asString() == "finally" }!!
if (context is JsIrBackendContext && (testFun.returnType as? IrSimpleType)?.isPromise == true) {
val refType = IrSimpleTypeImpl(context.ir.symbols.functionN(0), false, emptyList(), emptyList())
val afterFunction = context.irFactory.buildFun {
@@ -204,12 +209,14 @@ class TestGenerator(val context: JsCommonBackendContext, val groupByPackage: Boo
val finallyLambda = JsIrBuilder.buildFunctionExpression(refType, afterFunction)
val returnValue = JsIrBuilder.buildCall(
finally.symbol
).apply {
this.dispatchReceiver = returnStatement.value
putValueArgument(0, finallyLambda)
}
val finally =
IrDynamicMemberExpressionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.dynamicType, "finally", returnStatement.value)
val returnValue =
IrDynamicOperatorExpressionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.dynamicType, IrDynamicOperator.INVOKE).also {
it.receiver = finally
it.arguments.add(finallyLambda)
}
body.statements += JsIrBuilder.buildReturn(
fn.symbol,
@@ -261,4 +268,10 @@ class TestGenerator(val context: JsCommonBackendContext, val groupByPackage: Boo
private fun IrAnnotationContainer.hasAnnotation(fqName: String) =
annotations.any { it.symbol.owner.fqNameWhenAvailable?.parent()?.asString() == fqName }
private val IrSimpleType.isPromise: Boolean
get() {
val klass = classifier.owner as? IrClass ?: return false
return klass.isExternal && klass.getJsModule() == null && klass.getJsNameOrKotlinName().asString() == "Promise"
}
}
@@ -4,6 +4,7 @@ module.exports = {
'SimpleTest testFooWrong': 'pending',
'TestTest emptyTest': 'pending',
'AsyncTest checkAsyncOrder': 'pass',
'AsyncTest checkCustomPromise': 'pass',
'AsyncTest asyncPassing': 'pass',
'AsyncTest asyncFailing': 'fail',
'org OrgTest test': 'pass',
@@ -46,28 +46,33 @@ class AsyncTest {
var afterLog = ""
var expectedAfterLog = ""
@BeforeTest
fun before() {
log = ""
afterLog = ""
expectedAfterLog = ""
}
// Until bootstrap update
@AfterTest
fun after() {
assertEquals(afterLog, "after")
assertEquals(afterLog, expectedAfterLog)
}
fun promise(v: Int) = Promise<Int> { resolve, reject ->
fun promise(v: Int, after: String = "") = Promise<Int> { resolve, reject ->
log += "a"
js("setTimeout")({ log += "c"; afterLog += "after"; resolve(v) }, 100)
js("setTimeout")({ log += "c"; afterLog += after; resolve(v) }, 100)
log += "b"
}.also {
expectedAfterLog += after
}
@Test
fun checkAsyncOrder(): Promise<Unit> {
log += 1
val p1 = promise(10)
val p1 = promise(10, "after")
log += 2
@@ -80,9 +85,18 @@ class AsyncTest {
return p2
}
@Test
fun checkCustomPromise(): CustomPromise {
// return promise(10, "afterCustom") as CustomPromise
return promise(10, "") as CustomPromise
}
@Test
fun asyncPassing() = promise(10).then { assertEquals(10, it) }
@Test
fun asyncFailing() = promise(20).then { assertEquals(10, it) }
}
}
@JsName("Promise")
external class CustomPromise {}