[K/JS] Rework kotlin tests compilation to make it works with per-file granularity ^KT-61525 Fixed
This commit is contained in:
+1
-1
@@ -47,7 +47,7 @@ interface JsCommonBackendContext : CommonBackendContext {
|
||||
val enumEntries: IrClassSymbol
|
||||
val createEnumEntries: IrSimpleFunctionSymbol
|
||||
|
||||
fun createTestContainerFun(irFile: IrFile): IrSimpleFunction
|
||||
fun createTestContainerFun(container: IrDeclaration): IrSimpleFunction
|
||||
|
||||
}
|
||||
|
||||
|
||||
+11
-8
@@ -120,14 +120,17 @@ class JsIrBackendContext(
|
||||
|
||||
val testFunsPerFile = hashMapOf<IrFile, IrSimpleFunction>()
|
||||
|
||||
override fun createTestContainerFun(irFile: IrFile): IrSimpleFunction {
|
||||
return testFunsPerFile.getOrPut(irFile) {
|
||||
irFactory.addFunction(irFile) {
|
||||
name = Name.identifier("test fun")
|
||||
returnType = irBuiltIns.unitType
|
||||
origin = JsIrBuilder.SYNTHESIZED_DECLARATION
|
||||
}.apply {
|
||||
body = irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET, emptyList())
|
||||
override fun createTestContainerFun(container: IrDeclaration): IrSimpleFunction {
|
||||
val irFile = container.file
|
||||
return irFactory.stageController.restrictTo(container) {
|
||||
testFunsPerFile.getOrPut(irFile) {
|
||||
irFactory.addFunction(irFile) {
|
||||
name = Name.identifier("test fun")
|
||||
returnType = irBuiltIns.unitType
|
||||
origin = JsIrBuilder.SYNTHESIZED_DECLARATION
|
||||
}.apply {
|
||||
body = irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET, emptyList())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -244,4 +244,4 @@ internal fun CrossModuleReferences.crossModuleReferencesHashForIC() = HashCalcul
|
||||
update(import.moduleExporter.internalName.toString())
|
||||
}
|
||||
}
|
||||
}.finalizeAndGetHash()
|
||||
}.finalizeAndGetHash()
|
||||
+108
-42
@@ -30,7 +30,7 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
||||
|
||||
private fun SrcFileArtifact.loadJsIrModuleHeaders(moduleArtifact: ModuleArtifact) = with(loadJsIrFragments()!!) {
|
||||
LoadedJsIrModuleHeaders(
|
||||
mainFragment.mainFunction,
|
||||
mainFragment.mainFunctionTag,
|
||||
mainFragment.run {
|
||||
asIrModuleHeader(
|
||||
getMainFragmentExternalName(moduleArtifact),
|
||||
@@ -83,7 +83,10 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
||||
protected open val filePrefix by lazy(LazyThreadSafetyMode.NONE) { fileArtifact.srcFilePath.run { "${substringAfterLast('/')}.${cityHash64()}" } }
|
||||
|
||||
override fun loadJsIrModule(): JsIrModule {
|
||||
val fragments = fileArtifact.loadJsIrFragments()!!
|
||||
val fragments = fileArtifact.loadJsIrFragments()!!.also {
|
||||
it.mainFragment.testEnvironment = null
|
||||
}
|
||||
|
||||
val isExportFileCachedInfo = this is ExportFileCachedInfo
|
||||
return JsIrModule(
|
||||
jsIrHeader.moduleName,
|
||||
@@ -97,6 +100,7 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
||||
open class MainFileCachedInfo(moduleArtifact: ModuleArtifact, fileArtifact: SrcFileArtifact, moduleHeader: JsIrModuleHeader? = null) :
|
||||
SerializableCachedFileInfo(moduleArtifact, fileArtifact, moduleHeader) {
|
||||
var mainFunctionTag: String? = null
|
||||
var testEnvironment: JsIrProgramTestEnvironment? = null
|
||||
var exportFileCachedInfo: ExportFileCachedInfo? = null
|
||||
|
||||
val jsFileArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(CACHED_FILE_JS) }
|
||||
@@ -105,25 +109,27 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
||||
|
||||
class Merged(private val cachedFileInfos: List<MainFileCachedInfo>) :
|
||||
MainFileCachedInfo(cachedFileInfos.first().moduleArtifact, cachedFileInfos.first().fileArtifact) {
|
||||
override fun loadJsIrModule(): JsIrModule = cachedFileInfos.map { it.loadJsIrModule() }.merge()
|
||||
|
||||
override val filePrefix by lazy(LazyThreadSafetyMode.NONE) {
|
||||
val hash = cachedFileInfos.map { it.fileArtifact.srcFilePath }.sorted().joinToString().cityHash64()
|
||||
fileArtifact.srcFilePath.run { "${substringAfterLast('/')}.$hash.merged" }
|
||||
}
|
||||
|
||||
override fun loadJsIrModule(): JsIrModule = cachedFileInfos.map { it.loadJsIrModule() }.merge()
|
||||
|
||||
init {
|
||||
assert(cachedFileInfos.size > 1) { "Merge is unnecessary" }
|
||||
val isModified = cachedFileInfos.any { it.fileArtifact.isModified() }
|
||||
var isModified = false
|
||||
|
||||
for (info in cachedFileInfos) {
|
||||
if (!info.fileArtifact.isModified()) {
|
||||
isModified = true
|
||||
}
|
||||
info.testEnvironment?.let { testEnvironment = it }
|
||||
}
|
||||
|
||||
val mainAndExportHeaders = when {
|
||||
isModified -> cachedFileInfos.asSequence().map { it.fileArtifact.loadJsIrModuleHeaders(moduleArtifact) }
|
||||
else -> cachedFileInfos.asSequence().map {
|
||||
LoadedJsIrModuleHeaders(
|
||||
it.mainFunctionTag,
|
||||
it.jsIrHeader,
|
||||
it.exportFileCachedInfo?.jsIrHeader
|
||||
)
|
||||
}
|
||||
else -> cachedFileInfos.asSequence().map { LoadedJsIrModuleHeaders(it.mainFunctionTag, it.jsIrHeader, it.exportFileCachedInfo?.jsIrHeader) }
|
||||
}
|
||||
|
||||
val mainHeaders = mutableListOf<JsIrModuleHeader>()
|
||||
@@ -141,15 +147,13 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
||||
}
|
||||
|
||||
jsIrHeader = mainHeaders.merge()
|
||||
exportFileCachedInfo = exportHeaders
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?.let {
|
||||
ExportFileCachedInfo.Merged(
|
||||
filePrefix,
|
||||
it.merge(),
|
||||
cachedFileInfos.mapNotNull(MainFileCachedInfo::exportFileCachedInfo)
|
||||
)
|
||||
}
|
||||
exportFileCachedInfo = exportHeaders.takeIf { it.isNotEmpty() }?.let {
|
||||
ExportFileCachedInfo.Merged(
|
||||
filePrefix,
|
||||
it.merge(),
|
||||
cachedFileInfos.mapNotNull(MainFileCachedInfo::exportFileCachedInfo)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,6 +179,8 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
||||
class ModuleProxyFileCachedInfo(moduleArtifact: ModuleArtifact, moduleHeader: JsIrModuleHeader? = null) :
|
||||
CachedFileInfo(moduleArtifact, moduleHeader) {
|
||||
var mainFunctionTag: String? = null
|
||||
var suiteFunctionTag: String? = null
|
||||
var packagesToItsTestFunctions: CachedTestFunctionsWithTheirPackage = emptyMap()
|
||||
|
||||
val jsFileArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(CACHED_FILE_JS) }
|
||||
val dtsFileArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(CACHED_FILE_D_TS) }
|
||||
@@ -187,6 +193,8 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
||||
jsIrHeader.externalModuleName,
|
||||
jsIrHeader.externalModuleName,
|
||||
mainFunctionTag,
|
||||
suiteFunctionTag,
|
||||
packagesToItsTestFunctions,
|
||||
jsIrHeader.importedWithEffectInModuleWithName
|
||||
)
|
||||
}
|
||||
@@ -201,9 +209,20 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
||||
|
||||
it.crossFileReferencesHash = ICHash.fromProtoStream(this)
|
||||
|
||||
if (it is CachedFileInfo.ExportFileCachedInfo) {
|
||||
it.tsDeclarationsHash = runIf(readBool()) { readInt64() }
|
||||
reexportedIn = cachedFileInfo.moduleArtifact.moduleExternalName
|
||||
when (it) {
|
||||
is CachedFileInfo.MainFileCachedInfo -> {
|
||||
it.mainFunctionTag = ifTrue { readString() }
|
||||
it.testEnvironment = ifTrue { JsIrProgramTestEnvironment(readString(), readString()) }
|
||||
}
|
||||
is CachedFileInfo.ExportFileCachedInfo -> {
|
||||
it.tsDeclarationsHash = ifTrue { readInt64() }
|
||||
reexportedIn = cachedFileInfo.moduleArtifact.moduleExternalName
|
||||
}
|
||||
is CachedFileInfo.ModuleProxyFileCachedInfo -> {
|
||||
it.mainFunctionTag = ifTrue { readString() }
|
||||
it.suiteFunctionTag = ifTrue { readString() }
|
||||
it.packagesToItsTestFunctions = loadTestFunctions()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -222,6 +241,14 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
||||
)
|
||||
}
|
||||
|
||||
private fun CodedInputStream.loadTestFunctions() = buildMap {
|
||||
repeat(readInt32()) {
|
||||
put(readString(), buildList {
|
||||
repeat(readInt32()) { add(readString()) }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> CachedFileInfo.MainFileCachedInfo.readModuleHeaderCache(f: CodedInputStream.() -> T): T? =
|
||||
moduleHeaderArtifact?.useCodedInputIfExists(f)
|
||||
|
||||
@@ -231,7 +258,6 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
||||
return mainFileCachedFileInfo.readModuleHeaderCache {
|
||||
mainFileCachedFileInfo.apply {
|
||||
exportFileCachedInfo = fetchFileInfoForExportedPart(this)
|
||||
mainFunctionTag = ifTrue { readString() }
|
||||
loadSingleCachedFileInfo(this)
|
||||
}
|
||||
}
|
||||
@@ -239,10 +265,7 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
||||
|
||||
private fun ModuleArtifact.fetchModuleProxyFileInfo(): CachedFileInfo.ModuleProxyFileCachedInfo? {
|
||||
val mainFileCachedFileInfo = CachedFileInfo.ModuleProxyFileCachedInfo(this)
|
||||
return mainFileCachedFileInfo.moduleHeaderArtifact?.useCodedInputIfExists {
|
||||
mainFileCachedFileInfo.mainFunctionTag = ifTrue { readString() }
|
||||
loadSingleCachedFileInfo(mainFileCachedFileInfo)
|
||||
}
|
||||
return mainFileCachedFileInfo.moduleHeaderArtifact?.useCodedInputIfExists { loadSingleCachedFileInfo(mainFileCachedFileInfo) }
|
||||
}
|
||||
|
||||
private fun CodedInputStream.fetchFileInfoForExportedPart(mainCachedFileInfo: CachedFileInfo.MainFileCachedInfo): CachedFileInfo.ExportFileCachedInfo? {
|
||||
@@ -256,24 +279,43 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
||||
private fun CodedOutputStream.commitSingleFileInfo(cachedFileInfo: CachedFileInfo) {
|
||||
writeStringNoTag(cachedFileInfo.jsIrHeader.externalModuleName)
|
||||
cachedFileInfo.crossFileReferencesHash.toProtoStream(this)
|
||||
if (cachedFileInfo is CachedFileInfo.ExportFileCachedInfo) {
|
||||
ifNotNull(cachedFileInfo.tsDeclarationsHash, ::writeInt64NoTag)
|
||||
when (cachedFileInfo) {
|
||||
is CachedFileInfo.MainFileCachedInfo -> {
|
||||
ifNotNull(cachedFileInfo.mainFunctionTag, ::writeStringNoTag)
|
||||
ifNotNull(cachedFileInfo.testEnvironment) {
|
||||
writeStringNoTag(it.testFunctionTag)
|
||||
writeStringNoTag(it.suiteFunctionTag)
|
||||
}
|
||||
}
|
||||
is CachedFileInfo.ExportFileCachedInfo -> ifNotNull(cachedFileInfo.tsDeclarationsHash, ::writeInt64NoTag)
|
||||
is CachedFileInfo.ModuleProxyFileCachedInfo -> {
|
||||
ifNotNull(cachedFileInfo.mainFunctionTag, ::writeStringNoTag)
|
||||
ifNotNull(cachedFileInfo.suiteFunctionTag, ::writeStringNoTag)
|
||||
writeTestFunctions(cachedFileInfo.packagesToItsTestFunctions)
|
||||
}
|
||||
}
|
||||
ifNotNull(cachedFileInfo.jsIrHeader.importedWithEffectInModuleWithName) { writeStringNoTag(it) }
|
||||
commitJsIrModuleHeaderNames(cachedFileInfo.jsIrHeader)
|
||||
}
|
||||
|
||||
private fun CodedOutputStream.writeTestFunctions(cachedTestFunctionsWithTheirPackage: CachedTestFunctionsWithTheirPackage) {
|
||||
writeInt32NoTag(cachedTestFunctionsWithTheirPackage.size)
|
||||
cachedTestFunctionsWithTheirPackage.forEach { (key, value) ->
|
||||
writeStringNoTag(key)
|
||||
writeInt32NoTag(value.size)
|
||||
value.forEach(::writeStringNoTag)
|
||||
}
|
||||
}
|
||||
|
||||
private fun CachedFileInfo.commitFileInfo() = when (this) {
|
||||
is CachedFileInfo.MainFileCachedInfo -> {
|
||||
moduleHeaderArtifact?.useCodedOutput {
|
||||
ifNotNull(exportFileCachedInfo) { commitSingleFileInfo(it) }
|
||||
ifNotNull(mainFunctionTag) { writeStringNoTag(it) }
|
||||
commitSingleFileInfo(this@commitFileInfo)
|
||||
}
|
||||
}
|
||||
is CachedFileInfo.ModuleProxyFileCachedInfo -> {
|
||||
moduleHeaderArtifact?.useCodedOutput {
|
||||
ifNotNull(mainFunctionTag) { writeStringNoTag(it) }
|
||||
commitSingleFileInfo(this@commitFileInfo)
|
||||
}
|
||||
}
|
||||
@@ -282,26 +324,39 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
||||
|
||||
private fun ModuleArtifact.generateModuleProxyFileCachedInfo(
|
||||
mainFunctionTag: String?,
|
||||
suiteFunctionTag: String?,
|
||||
cachedTestFunctionsWithTheirPackage: CachedTestFunctionsWithTheirPackage,
|
||||
importedWithEffectInModuleWithName: String? = null
|
||||
): CachedFileInfo {
|
||||
val moduleHeader = generateProxyIrModuleWith(
|
||||
moduleExternalName,
|
||||
moduleExternalName,
|
||||
mainFunctionTag,
|
||||
suiteFunctionTag,
|
||||
cachedTestFunctionsWithTheirPackage,
|
||||
importedWithEffectInModuleWithName
|
||||
).makeModuleHeader()
|
||||
return CachedFileInfo.ModuleProxyFileCachedInfo(this, moduleHeader)
|
||||
.also { it.mainFunctionTag = mainFunctionTag }
|
||||
.also {
|
||||
it.mainFunctionTag = mainFunctionTag
|
||||
it.suiteFunctionTag = suiteFunctionTag
|
||||
it.packagesToItsTestFunctions = cachedTestFunctionsWithTheirPackage
|
||||
}
|
||||
}
|
||||
|
||||
private fun ModuleArtifact.loadFileInfoFor(fileArtifact: SrcFileArtifact): CachedFileInfo.MainFileCachedInfo {
|
||||
val headers = fileArtifact.loadJsIrModuleHeaders(this)
|
||||
val mainFragment =
|
||||
headers.mainHeader.associatedModule?.fragments?.single() ?: error("Unexpected multiple fragments inside mainHeader")
|
||||
|
||||
val mainCachedFileInfo = CachedFileInfo.MainFileCachedInfo(this, fileArtifact, headers.mainHeader)
|
||||
.apply { mainFunctionTag = headers.mainFunctionTag }
|
||||
val mainCachedFileInfo = CachedFileInfo.MainFileCachedInfo(this, fileArtifact, headers.mainHeader).apply {
|
||||
mainFunctionTag = headers.mainFunctionTag
|
||||
testEnvironment = mainFragment.testEnvironment
|
||||
mainFragment.testEnvironment = null
|
||||
}
|
||||
|
||||
if (headers.exportHeader != null) {
|
||||
val tsDeclarationsHash = fileArtifact.loadJsIrFragments()?.exportFragment?.dts?.raw?.cityHash64()
|
||||
val tsDeclarationsHash = headers.exportHeader.associatedModule?.fragments?.single()?.dts?.raw?.cityHash64()
|
||||
val cachedExportFileInfo = mainCachedFileInfo.readModuleHeaderCache { fetchFileInfoForExportedPart(mainCachedFileInfo) }
|
||||
mainCachedFileInfo.exportFileCachedInfo = if (cachedExportFileInfo?.tsDeclarationsHash != tsDeclarationsHash) {
|
||||
CachedFileInfo.ExportFileCachedInfo(
|
||||
@@ -351,7 +406,7 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
||||
override val CachedFileInfo.artifactName get() = jsIrHeader.externalModuleName
|
||||
override val CachedFileInfo.hasEffect get() = jsIrHeader.importedWithEffectInModuleWithName != null
|
||||
override val CachedFileInfo.hasExport get() = this is CachedFileInfo.MainFileCachedInfo && exportFileCachedInfo != null
|
||||
override val CachedFileInfo.packageFqn get() = moduleFragmentToExternalName.excludeFileNameFromExternalName(jsIrHeader.moduleName)
|
||||
override val CachedFileInfo.packageFqn get() = moduleFragmentToExternalName.getPackageFqn(jsIrHeader.moduleName)
|
||||
override val CachedFileInfo.mainFunction
|
||||
get() = when (this) {
|
||||
is CachedFileInfo.MainFileCachedInfo -> mainFunctionTag
|
||||
@@ -359,6 +414,9 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
||||
else -> error("Unexpected CachedFileInfo type ${this::class.simpleName}")
|
||||
}
|
||||
|
||||
override fun CachedFileInfo.takeTestEnvironmentOwnership() =
|
||||
(this as CachedFileInfo.MainFileCachedInfo).testEnvironment
|
||||
|
||||
override fun SrcFileArtifact.generateArtifact(module: ModuleArtifact) = when {
|
||||
isModified() -> module.loadFileInfoFor(this)
|
||||
else -> module.fetchFileInfoFor(this) ?: module.loadFileInfoFor(this)
|
||||
@@ -370,10 +428,18 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
||||
else -> CachedFileInfo.MainFileCachedInfo.Merged(map { it as CachedFileInfo.MainFileCachedInfo })
|
||||
}
|
||||
|
||||
override fun ModuleArtifact.generateArtifact(mainFunctionTag: String?, moduleNameForEffects: String?) =
|
||||
fetchModuleProxyFileInfo()?.takeIf {
|
||||
it.mainFunction == mainFunctionTag && it.jsIrHeader.importedWithEffectInModuleWithName == moduleNameForEffects
|
||||
} ?: generateModuleProxyFileCachedInfo(mainFunctionTag, moduleNameForEffects)
|
||||
override fun ModuleArtifact.generateArtifact(
|
||||
mainFunctionTag: String?,
|
||||
suiteFunctionTag: String?,
|
||||
testFunctions: CachedTestFunctionsWithTheirPackage,
|
||||
moduleNameForEffects: String?
|
||||
) = fetchModuleProxyFileInfo()?.takeIf {
|
||||
it.mainFunctionTag == mainFunctionTag
|
||||
&& it.jsIrHeader.importedWithEffectInModuleWithName == moduleNameForEffects
|
||||
&& suiteFunctionTag == it.suiteFunctionTag &&
|
||||
it.packagesToItsTestFunctions == testFunctions &&
|
||||
it.jsIrHeader.importedWithEffectInModuleWithName == moduleNameForEffects
|
||||
} ?: generateModuleProxyFileCachedInfo(mainFunctionTag, suiteFunctionTag, testFunctions, moduleNameForEffects)
|
||||
}
|
||||
|
||||
return perFileGenerator.generatePerFileArtifacts(moduleArtifacts)
|
||||
|
||||
+6
-3
@@ -46,7 +46,7 @@ class TestGenerator(val context: JsCommonBackendContext, val groupByPackage: Boo
|
||||
if (irFile.declarations.isEmpty()) return
|
||||
ArrayList(irFile.declarations).forEach {
|
||||
if (it is IrClass) {
|
||||
generateTestCalls(it) { if (groupByPackage) suiteForPackage(irFile) else context.createTestContainerFun(irFile) }
|
||||
generateTestCalls(it) { if (groupByPackage) suiteForPackage(it) else context.createTestContainerFun(it) }
|
||||
}
|
||||
|
||||
// TODO top-level functions
|
||||
@@ -55,8 +55,11 @@ class TestGenerator(val context: JsCommonBackendContext, val groupByPackage: Boo
|
||||
|
||||
private val packageSuites = hashMapOf<FqName, IrSimpleFunction>()
|
||||
|
||||
private fun suiteForPackage(irFile: IrFile) = packageSuites.getOrPut(irFile.packageFqName) {
|
||||
context.suiteFun!!.createInvocation(irFile.packageFqName.asString(), context.createTestContainerFun(irFile))
|
||||
private fun suiteForPackage(container: IrDeclaration): IrSimpleFunction {
|
||||
val irFile = container.file
|
||||
return packageSuites.getOrPut(irFile.packageFqName) {
|
||||
context.suiteFun!!.createInvocation(irFile.packageFqName.asString(), context.createTestContainerFun(container))
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrSimpleFunctionSymbol.createInvocation(
|
||||
|
||||
+52
-24
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.serialization.checkIsFunctionInterfac
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.ir.backend.js.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.ic.JsPerFileCache
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.JsCodeOutliningLowering
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.StaticMembersLowering
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isBuiltInClass
|
||||
@@ -29,7 +30,6 @@ import org.jetbrains.kotlin.js.sourceMap.SourceMapBuilderConsumer
|
||||
import org.jetbrains.kotlin.js.util.TextOutputImpl
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
import org.jetbrains.kotlin.utils.memoryOptimizedMap
|
||||
import org.jetbrains.kotlin.utils.putToMultiMap
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||
import java.io.File
|
||||
@@ -51,15 +51,28 @@ val IrModuleFragment.safeName: String
|
||||
fun generateProxyIrModuleWith(
|
||||
safeName: String,
|
||||
externalName: String,
|
||||
mainFunction: String?,
|
||||
mainFunctionTag: String?,
|
||||
suiteFunctionTag: String? = null,
|
||||
cachedTestFunctionsWithTheirPackage: CachedTestFunctionsWithTheirPackage = emptyMap(),
|
||||
importedWithEffectInModuleWithName: String? = null
|
||||
): JsIrModule {
|
||||
val programFragment = JsIrProgramFragment(safeName, "<proxy-file>").apply {
|
||||
mainFunction?.let {
|
||||
this.mainFunction = it
|
||||
this.nameBindings[it] = JsName("main", true)
|
||||
mainFunctionTag?.let {
|
||||
this.mainFunctionTag = it
|
||||
nameBindings[it] = ReservedJsNames.makeMainFunctionName()
|
||||
}
|
||||
cachedTestFunctionsWithTheirPackage.takeIf { it.isNotEmpty() }?.let {
|
||||
nameBindings += it.values.asSequence()
|
||||
.flatten()
|
||||
.map { tag -> tag to ReservedJsNames.makeTestFunctionName() }
|
||||
.plus(suiteFunctionTag!! to ReservedJsNames.makeSuiteFunctionName())
|
||||
|
||||
JsTestFunctionTransformer.generateTestFunctionCall(
|
||||
it.asTestFunctionContainers(suiteFunctionTag, nameBindings)
|
||||
)?.run { declarations.statements += makeStmt() }
|
||||
}
|
||||
}
|
||||
|
||||
return JsIrModule(
|
||||
safeName,
|
||||
externalName,
|
||||
@@ -276,25 +289,35 @@ class IrModuleToJsTransformer(
|
||||
}
|
||||
|
||||
private fun generateJsIrProgramPerFile(exportData: List<IrAndExportedDeclarations>, mode: TranslationMode): JsIrProgram {
|
||||
val mainModule = exportData.last()
|
||||
val mainModuleWithExportedData = exportData.last()
|
||||
|
||||
val perFileGenerator = object : PerFileGenerator<IrAndExportedDeclarations, IrFileExports, JsIrModules> {
|
||||
override val mainModuleName get() = mainModule.fragment.safeName
|
||||
override val mainModuleName = mainModuleWithExportedData.fragment.safeName
|
||||
private val JsIrModules.mainFragment get() = mainModule.fragments.first()
|
||||
|
||||
override val IrAndExportedDeclarations.isMain get() = this === mainModule
|
||||
override val IrAndExportedDeclarations.isMain get() = this === mainModuleWithExportedData
|
||||
override val IrAndExportedDeclarations.fileList get() = files
|
||||
|
||||
override val JsIrModules.artifactName get() = this.mainModule.externalModuleName
|
||||
override val JsIrModules.hasEffect get() = this.mainModule.importedWithEffectInModuleWithName != null
|
||||
override val JsIrModules.hasExport get() = this.exportModule != null
|
||||
override val JsIrModules.packageFqn get() = this.mainModule.fragments.first().packageFqn
|
||||
override val JsIrModules.mainFunction get() = this.mainModule.fragments.first().mainFunction
|
||||
override val JsIrModules.artifactName get() = mainModule.externalModuleName
|
||||
override val JsIrModules.hasEffect get() = mainModule.importedWithEffectInModuleWithName != null
|
||||
override val JsIrModules.hasExport get() = exportModule != null
|
||||
override val JsIrModules.packageFqn get() = mainFragment.packageFqn
|
||||
override val JsIrModules.mainFunction get() = mainFragment.mainFunctionTag
|
||||
|
||||
override fun JsIrModules.takeTestEnvironmentOwnership(): JsIrProgramTestEnvironment? {
|
||||
val fragment = mainFragment
|
||||
return fragment.testEnvironment.also { fragment.testEnvironment = null }
|
||||
}
|
||||
|
||||
override fun List<JsIrModules>.merge() =
|
||||
JsIrModules(map { it.mainModule }.merge(), mapNotNull { it.exportModule }.ifNotEmpty { merge() })
|
||||
|
||||
override fun IrAndExportedDeclarations.generateArtifact(mainFunctionTag: String?, moduleNameForEffects: String?) =
|
||||
JsIrModules(toJsIrProxyModule(mainFunctionTag, moduleNameForEffects))
|
||||
override fun IrAndExportedDeclarations.generateArtifact(
|
||||
mainFunctionTag: String?,
|
||||
suiteFunctionTag: String?,
|
||||
testFunctions: CachedTestFunctionsWithTheirPackage,
|
||||
moduleNameForEffects: String?
|
||||
) = JsIrModules(toJsIrProxyModule(mainFunctionTag, suiteFunctionTag, testFunctions, moduleNameForEffects))
|
||||
|
||||
override fun IrFileExports.generateArtifact(module: IrAndExportedDeclarations) = takeIf { !file.couldBeSkipped() }
|
||||
?.let { generateProgramFragment(it, mode) }
|
||||
@@ -332,13 +355,17 @@ class IrModuleToJsTransformer(
|
||||
}
|
||||
|
||||
private fun IrAndExportedDeclarations.toJsIrProxyModule(
|
||||
mainFunction: String?,
|
||||
mainFunctionTag: String?,
|
||||
suiteFunctionTag: String?,
|
||||
cachedTestFunctionsWithTheirPackage: CachedTestFunctionsWithTheirPackage,
|
||||
importedWithEffectInModuleWithName: String? = null
|
||||
): JsIrModule {
|
||||
return generateProxyIrModuleWith(
|
||||
fragment.safeName,
|
||||
moduleFragmentToNameMapper.getExternalNameFor(fragment),
|
||||
mainFunction,
|
||||
mainFunctionTag,
|
||||
suiteFunctionTag,
|
||||
cachedTestFunctionsWithTheirPackage,
|
||||
importedWithEffectInModuleWithName
|
||||
)
|
||||
}
|
||||
@@ -422,12 +449,6 @@ class IrModuleToJsTransformer(
|
||||
|
||||
result.initializers.statements += staticContext.initializerBlock.statements
|
||||
result.eagerInitializers.statements += staticContext.eagerInitializerBlock.statements
|
||||
|
||||
backendContext.testFunsPerFile[fileExports.file]?.let {
|
||||
result.testFunInvocation = JsInvocation(staticContext.getNameForStaticFunction(it).makeRef()).makeStmt()
|
||||
result.suiteFn = staticContext.getNameForStaticFunction(backendContext.suiteFun!!.owner)
|
||||
}
|
||||
|
||||
result.importedModules += nameGenerator.importedModules
|
||||
|
||||
val definitionSet = fileExports.file.declarations.toSet()
|
||||
@@ -435,9 +456,16 @@ class IrModuleToJsTransformer(
|
||||
if (shouldReferMainFunction) {
|
||||
JsMainFunctionDetector(backendContext).getMainFunctionOrNull(fileExports.file)
|
||||
?.let { backendContext.mapping.mainFunctionToItsWrapper[it] }
|
||||
?.let { result.mainFunction = definitionSet.computeTag(it) }
|
||||
?.let { result.mainFunctionTag = definitionSet.computeTag(it) }
|
||||
}
|
||||
|
||||
backendContext.testFunsPerFile[fileExports.file]
|
||||
?.let { definitionSet.computeTag(it) }
|
||||
?.let {
|
||||
val suiteFunctionTag = definitionSet.computeTag(backendContext.suiteFun!!.owner) ?: error("Expect suite function tag exists")
|
||||
result.testEnvironment = JsIrProgramTestEnvironment(it, suiteFunctionTag)
|
||||
}
|
||||
|
||||
result.computeAndSaveNameBindings(definitionSet, nameGenerator)
|
||||
result.computeAndSaveImports(definitionSet, nameGenerator)
|
||||
result.computeAndSaveDefinitions(definitionSet, fileExports)
|
||||
|
||||
+7
-3
@@ -14,6 +14,11 @@ import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
|
||||
class JsIrProgramFragments(val mainFragment: JsIrProgramFragment, val exportFragment: JsIrProgramFragment? = null)
|
||||
|
||||
data class JsIrProgramTestEnvironment(
|
||||
val testFunctionTag: String,
|
||||
val suiteFunctionTag: String
|
||||
)
|
||||
|
||||
class JsIrProgramFragment(val name: String, val packageFqn: String) {
|
||||
val nameBindings = mutableMapOf<String, JsName>()
|
||||
val optionalCrossModuleImports = hashSetOf<String>()
|
||||
@@ -25,11 +30,10 @@ class JsIrProgramFragment(val name: String, val packageFqn: String) {
|
||||
val classes = mutableMapOf<JsName, JsIrIcClassModel>()
|
||||
val initializers = JsCompositeBlock()
|
||||
val eagerInitializers = JsCompositeBlock()
|
||||
var mainFunction: String? = null
|
||||
var testFunInvocation: JsStatement? = null
|
||||
var suiteFn: JsName? = null
|
||||
var mainFunctionTag: String? = null
|
||||
val definitions = mutableSetOf<String>()
|
||||
val polyfills = JsCompositeBlock()
|
||||
var testEnvironment: JsIrProgramTestEnvironment? = null
|
||||
}
|
||||
|
||||
class JsIrModule(
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
|
||||
object JsTestFunctionTransformer {
|
||||
fun generateTestFunctionCall(testFunctionContainers: List<TestFunctionContainer>): JsInvocation? {
|
||||
if (testFunctionContainers.isEmpty()) return null
|
||||
|
||||
val testFunBody = JsBlock()
|
||||
val testFun = JsFunction(emptyScope, testFunBody, "root test fun")
|
||||
val suiteFunRef = testFunctionContainers.firstNotNullOf { it.suiteFunctionName }.makeRef()
|
||||
|
||||
val tests = testFunctionContainers.groupBy({ it.packageFqn }) {
|
||||
JsInvocation(it.testFunctionName.makeRef()).makeStmt()
|
||||
} // String -> [IrSimpleFunction]
|
||||
|
||||
for ((pkg, testCalls) in tests) {
|
||||
val pkgTestFun = JsFunction(emptyScope, JsBlock(), "test fun for $pkg")
|
||||
pkgTestFun.body.statements += testCalls
|
||||
testFun.body.statements += JsInvocation(suiteFunRef, JsStringLiteral(pkg), JsBooleanLiteral(false), pkgTestFun).makeStmt()
|
||||
}
|
||||
|
||||
return JsInvocation(testFun)
|
||||
}
|
||||
|
||||
class TestFunctionContainer(
|
||||
val packageFqn: String,
|
||||
val testFunctionName: JsName,
|
||||
val suiteFunctionName: JsName
|
||||
)
|
||||
}
|
||||
|
||||
private fun Map<String, JsName>.getTestFunctionBySignature(signature: String?): JsName {
|
||||
return get(signature) ?: error("Null test functions should be filtered on a previous step")
|
||||
}
|
||||
|
||||
private fun Map<String, JsName>.getSuiteFunctionBySignature(signature: String?): JsName {
|
||||
return get(signature) ?: error("A Suite function signature should be present if a test function signature does")
|
||||
}
|
||||
|
||||
fun List<JsIrProgramFragment>.asTestFunctionContainers(): List<JsTestFunctionTransformer.TestFunctionContainer> {
|
||||
return mapNotNull { fragment ->
|
||||
fragment.testEnvironment?.let {
|
||||
JsTestFunctionTransformer.TestFunctionContainer(
|
||||
fragment.packageFqn,
|
||||
fragment.nameBindings.getTestFunctionBySignature(it.testFunctionTag),
|
||||
fragment.nameBindings.getSuiteFunctionBySignature(it.suiteFunctionTag)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun CachedTestFunctionsWithTheirPackage.asTestFunctionContainers(
|
||||
suiteFunction: String?,
|
||||
nameBindings: Map<String, JsName>
|
||||
): List<JsTestFunctionTransformer.TestFunctionContainer> {
|
||||
return entries.flatMap { (packageFqn, testFunctions) ->
|
||||
testFunctions.map {
|
||||
JsTestFunctionTransformer.TestFunctionContainer(
|
||||
packageFqn,
|
||||
nameBindings.getTestFunctionBySignature(it),
|
||||
nameBindings.getSuiteFunctionBySignature(suiteFunction),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-20
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
|
||||
import org.jetbrains.kotlin.idea.MainFunctionDetector
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsMainFunctionDetector
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
@@ -61,8 +60,6 @@ class Merger(
|
||||
|
||||
rename(f.initializers)
|
||||
rename(f.eagerInitializers)
|
||||
f.testFunInvocation?.let { rename(it) }
|
||||
f.suiteFn?.let { f.suiteFn = rename(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,27 +226,14 @@ class Merger(
|
||||
moduleBody.addWithComment("block: init", initializerBlock.statements)
|
||||
|
||||
// Merge test function invocations
|
||||
if (fragments.any { it.testFunInvocation != null }) {
|
||||
val testFunBody = JsBlock()
|
||||
val testFun = JsFunction(emptyScope, testFunBody, "root test fun")
|
||||
val suiteFunRef = fragments.firstNotNullOf { it.suiteFn }.makeRef()
|
||||
|
||||
val tests = fragments.filter { it.testFunInvocation != null }
|
||||
.groupBy({ it.packageFqn }) { it.testFunInvocation } // String -> [IrSimpleFunction]
|
||||
|
||||
for ((pkg, testCalls) in tests) {
|
||||
val pkgTestFun = JsFunction(emptyScope, JsBlock(), "test fun for $pkg")
|
||||
pkgTestFun.body.statements += testCalls
|
||||
testFun.body.statements += JsInvocation(suiteFunRef, JsStringLiteral(pkg), JsBooleanLiteral(false), pkgTestFun).makeStmt()
|
||||
}
|
||||
|
||||
JsTestFunctionTransformer.generateTestFunctionCall(fragments.asTestFunctionContainers())?.let {
|
||||
moduleBody.startRegion("block: tests")
|
||||
moduleBody += JsInvocation(testFun).makeStmt()
|
||||
moduleBody += it.makeStmt()
|
||||
moduleBody.endRegion()
|
||||
}
|
||||
|
||||
val fragmentWithMainFunction = JsMainFunctionDetector.pickMainFunctionFromCandidates(fragments) {
|
||||
JsMainFunctionDetector.MainFunctionCandidate(it.packageFqn, it.mainFunction)
|
||||
JsMainFunctionDetector.MainFunctionCandidate(it.packageFqn, it.mainFunctionTag)
|
||||
}
|
||||
|
||||
val exportStatements = declareAndCallJsExporter() + additionalExports + transitiveJsExport()
|
||||
@@ -271,7 +255,7 @@ class Merger(
|
||||
statements += moduleBody
|
||||
statements.addWithComment("block: exports", exportStatements)
|
||||
if (generateCallToMain && fragmentWithMainFunction != null) {
|
||||
val mainFunctionTag = fragmentWithMainFunction.mainFunction ?: error("Expect to have main function signature at this point")
|
||||
val mainFunctionTag = fragmentWithMainFunction.mainFunctionTag ?: error("Expect to have main function signature at this point")
|
||||
val mainFunctionName = fragmentWithMainFunction.nameBindings[mainFunctionTag] ?: error("Expect to have name binding for tag $mainFunctionTag")
|
||||
statements += JsInvocation(mainFunctionName.makeRef()).makeStmt()
|
||||
}
|
||||
|
||||
+11
-4
@@ -42,10 +42,6 @@ class ModuleFragmentToExternalName(private val jsOutputNamesMapping: Map<IrModul
|
||||
return module.getJsOutputName()
|
||||
}
|
||||
|
||||
fun excludeFileNameFromExternalName(externalName: String): String {
|
||||
return externalName.substringBeforeLast('/')
|
||||
}
|
||||
|
||||
private fun IrModuleFragment.getJsOutputName(): String {
|
||||
return jsOutputNamesMapping[this] ?: sanitizeName(safeName)
|
||||
}
|
||||
@@ -55,6 +51,17 @@ class ModuleFragmentToExternalName(private val jsOutputNamesMapping: Map<IrModul
|
||||
return "$prefix${if (prefix.isNotEmpty()) "/" else ""}$fileName"
|
||||
}
|
||||
|
||||
fun getPackageFqn(externalName: String): String {
|
||||
val endOfModuleNamePart = externalName.indexOf('/')
|
||||
val startOfFileNamePart = externalName.lastIndexOf('/')
|
||||
return if (endOfModuleNamePart == startOfFileNamePart) {
|
||||
""
|
||||
} else {
|
||||
externalName.substring(endOfModuleNamePart + 1, startOfFileNamePart)
|
||||
.replace('/', '.')
|
||||
}
|
||||
}
|
||||
|
||||
private val IrFile.outputName: String get() = getJsFileName() ?: nameWithoutExtension
|
||||
private val IrFile.stableFileName: String get() = getFileStableName(outputName, packageFqName.asString())
|
||||
}
|
||||
+31
-13
@@ -9,6 +9,8 @@ import org.jetbrains.kotlin.ir.backend.js.utils.JsMainFunctionDetector
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
import org.jetbrains.kotlin.utils.putToMultiMap
|
||||
|
||||
typealias CachedTestFunctionsWithTheirPackage = Map<String, List<String>>
|
||||
|
||||
interface PerFileGenerator<Module, File, Artifact> {
|
||||
val mainModuleName: String
|
||||
|
||||
@@ -21,9 +23,16 @@ interface PerFileGenerator<Module, File, Artifact> {
|
||||
val Artifact.packageFqn: String
|
||||
val Artifact.mainFunction: String?
|
||||
|
||||
fun Artifact.takeTestEnvironmentOwnership(): JsIrProgramTestEnvironment?
|
||||
|
||||
fun List<Artifact>.merge(): Artifact
|
||||
fun File.generateArtifact(module: Module): Artifact?
|
||||
fun Module.generateArtifact(mainFunctionTag: String?, moduleNameForEffects: String?): Artifact
|
||||
fun Module.generateArtifact(
|
||||
mainFunctionTag: String?,
|
||||
suiteFunctionTag: String?,
|
||||
testFunctions: CachedTestFunctionsWithTheirPackage,
|
||||
moduleNameForEffects: String?
|
||||
): Artifact
|
||||
|
||||
fun generatePerFileArtifacts(modules: List<Module>): List<Artifact> {
|
||||
var someModuleHasEffect = false
|
||||
@@ -32,6 +41,8 @@ interface PerFileGenerator<Module, File, Artifact> {
|
||||
for (module in modules) {
|
||||
var hasModuleLevelEffect = false
|
||||
var hasFileWithExportedDeclaration = false
|
||||
var suiteFunctionTag: String? = null
|
||||
val testFunctions = mutableMapOf<String, MutableList<String>>()
|
||||
|
||||
val artifacts = module.fileList.mapNotNull {
|
||||
val generatedArtifact = it.generateArtifact(module) ?: return@mapNotNull null
|
||||
@@ -44,6 +55,11 @@ interface PerFileGenerator<Module, File, Artifact> {
|
||||
hasModuleLevelEffect = true
|
||||
}
|
||||
|
||||
generatedArtifact.takeTestEnvironmentOwnership()?.let { (testFunction, suiteFunction) ->
|
||||
testFunctions.putToMultiMap(generatedArtifact.packageFqn, testFunction)
|
||||
suiteFunctionTag = suiteFunction
|
||||
}
|
||||
|
||||
putToMultiMap(generatedArtifact.artifactName, generatedArtifact)
|
||||
|
||||
generatedArtifact
|
||||
@@ -54,19 +70,21 @@ interface PerFileGenerator<Module, File, Artifact> {
|
||||
}
|
||||
|
||||
val mainFunctionTag = runIf(module.isMain) {
|
||||
JsMainFunctionDetector
|
||||
.pickMainFunctionFromCandidates(artifacts) {
|
||||
JsMainFunctionDetector.MainFunctionCandidate(
|
||||
it.packageFqn,
|
||||
it.mainFunction
|
||||
)
|
||||
}
|
||||
?.mainFunction
|
||||
JsMainFunctionDetector.pickMainFunctionFromCandidates(artifacts) {
|
||||
JsMainFunctionDetector.MainFunctionCandidate(
|
||||
it.packageFqn,
|
||||
it.mainFunction
|
||||
)
|
||||
}?.mainFunction
|
||||
}
|
||||
|
||||
if (mainFunctionTag != null || hasFileWithExportedDeclaration || hasModuleLevelEffect || (module.isMain && someModuleHasEffect)) {
|
||||
val proxyArtifact =
|
||||
module.generateArtifact(mainFunctionTag, mainModuleName.takeIf { !module.isMain && hasModuleLevelEffect }) ?: continue
|
||||
if (mainFunctionTag != null || hasFileWithExportedDeclaration || hasModuleLevelEffect || suiteFunctionTag != null || (module.isMain && someModuleHasEffect)) {
|
||||
val proxyArtifact = module.generateArtifact(
|
||||
mainFunctionTag,
|
||||
suiteFunctionTag,
|
||||
testFunctions,
|
||||
mainModuleName.takeIf { !module.isMain && hasModuleLevelEffect }
|
||||
) ?: continue
|
||||
putToMultiMap(proxyArtifact.artifactName, proxyArtifact)
|
||||
}
|
||||
}
|
||||
@@ -74,4 +92,4 @@ interface PerFileGenerator<Module, File, Artifact> {
|
||||
|
||||
return nameToModulePerFile.values.map { it.merge() }
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -13,5 +13,8 @@ class ReservedJsNames {
|
||||
fun makeInternalModuleName() = JsName("_", false)
|
||||
fun makeJsExporterName() = JsName("\$jsExportAll\$", false)
|
||||
fun makeCrossModuleNameRef(moduleName: JsName) = JsNameRef("\$_\$", moduleName.makeRef())
|
||||
fun makeMainFunctionName() = JsName("main", true)
|
||||
fun makeTestFunctionName() = JsName("test", true)
|
||||
fun makeSuiteFunctionName() = JsName("suite", true)
|
||||
}
|
||||
}
|
||||
+7
-3
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.ir.backend.js.export.TypeScriptFragment
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrIcClassModel
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragment
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragments
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramTestEnvironment
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.*
|
||||
@@ -103,10 +104,9 @@ private class JsIrAstDeserializer(private val source: ByteArray) {
|
||||
readRepeated { optionalCrossModuleImports.add(stringTable[readInt()]) }
|
||||
readRepeated { classes[nameTable[readInt()]] = readIrIcClassModel() }
|
||||
|
||||
ifTrue { testFunInvocation = readStatement() }
|
||||
ifTrue { mainFunction = readString() }
|
||||
ifTrue { mainFunctionTag = readString() }
|
||||
ifTrue { testEnvironment = readTestEnvironment() }
|
||||
ifTrue { dts = TypeScriptFragment(readString()) }
|
||||
ifTrue { suiteFn = nameTable[readInt()] }
|
||||
|
||||
readRepeated { definitions += stringTable[readInt()] }
|
||||
}
|
||||
@@ -119,6 +119,10 @@ private class JsIrAstDeserializer(private val source: ByteArray) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun readTestEnvironment(): JsIrProgramTestEnvironment {
|
||||
return JsIrProgramTestEnvironment(stringTable[readInt()], stringTable[readInt()])
|
||||
}
|
||||
|
||||
private fun readStatement(): JsStatement {
|
||||
return withComments {
|
||||
withLocation {
|
||||
|
||||
+5
-8
@@ -151,22 +151,19 @@ private class JsIrAstSerializer {
|
||||
writeIrIcModel(model)
|
||||
}
|
||||
|
||||
ifNotNull(fragment.testFunInvocation) {
|
||||
writeStatement(it)
|
||||
ifNotNull(fragment.mainFunctionTag) {
|
||||
writeString(it)
|
||||
}
|
||||
|
||||
ifNotNull(fragment.mainFunction) {
|
||||
writeString(it)
|
||||
ifNotNull(fragment.testEnvironment) {
|
||||
writeInt(internalizeString(it.testFunctionTag))
|
||||
writeInt(internalizeString(it.suiteFunctionTag))
|
||||
}
|
||||
|
||||
ifNotNull(fragment.dts) {
|
||||
writeString(it.raw)
|
||||
}
|
||||
|
||||
ifNotNull(fragment.suiteFn) {
|
||||
writeInt(internalizeName(it))
|
||||
}
|
||||
|
||||
writeCollection(fragment.definitions) {
|
||||
writeInt(internalizeString(it))
|
||||
}
|
||||
|
||||
+3
-1
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.ir.util.addChild
|
||||
import org.jetbrains.kotlin.ir.util.file
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
@@ -182,7 +183,8 @@ class WasmBackendContext(
|
||||
val testEntryPoints: Collection<IrSimpleFunction>
|
||||
get() = testContainerFuns.values
|
||||
|
||||
override fun createTestContainerFun(irFile: IrFile): IrSimpleFunction {
|
||||
override fun createTestContainerFun(container: IrDeclaration): IrSimpleFunction {
|
||||
val irFile = container.file
|
||||
val module = irFile.module
|
||||
return testContainerFuns.getOrPut(module) {
|
||||
val file = syntheticFile("tests", module)
|
||||
|
||||
@@ -269,6 +269,9 @@ fun Test.setUpJsBoxTests(jsEnabled: Boolean, jsIrEnabled: Boolean, firEnabled: B
|
||||
dependsOn(":kotlin-test:kotlin-test-js-ir:compileKotlinJs")
|
||||
systemProperty("kotlin.js.kotlin.test.path", "libraries/kotlin.test/js-ir/build/classes/kotlin/js/main")
|
||||
inputs.dir(rootDir.resolve("libraries/kotlin.test/js-ir/build/classes/kotlin/js/main"))
|
||||
|
||||
systemProperty("kotlin.js.kotlin.test.klib.path", "libraries/kotlin.test/js-ir/build/libs/kotlin-test-js-$version.klib")
|
||||
inputs.file(rootDir.resolve("libraries/kotlin.test/js-ir/build/libs/kotlin-test-js-$version.klib"))
|
||||
}
|
||||
|
||||
exclude("org/jetbrains/kotlin/js/testOld/api/*")
|
||||
|
||||
@@ -61,9 +61,11 @@ abstract class AbstractInvalidationTest(
|
||||
companion object {
|
||||
private val OUT_DIR_PATH = System.getProperty("kotlin.js.test.root.out.dir") ?: error("'kotlin.js.test.root.out.dir' is not set")
|
||||
private val STDLIB_KLIB = File(System.getProperty("kotlin.js.stdlib.klib.path") ?: error("Please set stdlib path")).canonicalPath
|
||||
private val KOTLIN_TEST_KLIB = File(System.getProperty("kotlin.js.kotlin.test.klib.path") ?: error("Please set kotlin.test path")).canonicalPath
|
||||
|
||||
private const val BOX_FUNCTION_NAME = "box"
|
||||
private const val STDLIB_MODULE_NAME = "kotlin-kotlin-stdlib"
|
||||
private const val KOTLIN_TEST_MODULE_NAME = "kotlin-kotlin-test"
|
||||
|
||||
private val TEST_FILE_IGNORE_PATTERN = Regex("^.*\\..+\\.\\w\\w$")
|
||||
|
||||
@@ -202,7 +204,7 @@ abstract class AbstractInvalidationTest(
|
||||
|
||||
val friends = mutableListOf<File>()
|
||||
if (moduleStep.rebuildKlib) {
|
||||
val dependencies = mutableListOf(File(STDLIB_KLIB))
|
||||
val dependencies = mutableListOf(File(STDLIB_KLIB), File(KOTLIN_TEST_KLIB))
|
||||
for (dep in moduleStep.dependencies) {
|
||||
val klibFile = resolveModuleArtifact(dep.moduleName, buildDir)
|
||||
dependencies += klibFile
|
||||
@@ -229,7 +231,7 @@ abstract class AbstractInvalidationTest(
|
||||
}
|
||||
|
||||
private fun verifyCacheUpdateStats(stepId: Int, stats: KotlinSourceFileMap<EnumSet<DirtyFileState>>, testInfo: List<TestStepInfo>) {
|
||||
val gotStats = stats.filter { it.key.path != STDLIB_KLIB }
|
||||
val gotStats = stats.filter { it.key.path != STDLIB_KLIB && it.key.path != KOTLIN_TEST_KLIB }
|
||||
|
||||
val checkedLibs = mutableSetOf<KotlinLibraryFile>()
|
||||
|
||||
@@ -260,7 +262,7 @@ abstract class AbstractInvalidationTest(
|
||||
}
|
||||
|
||||
private fun verifyJsExecutableProducerBuildModules(stepId: Int, gotRebuilt: List<String>, expectedRebuilt: List<String>) {
|
||||
val got = gotRebuilt.filter { !it.startsWith(STDLIB_MODULE_NAME) }
|
||||
val got = gotRebuilt.filter { !it.startsWith(STDLIB_MODULE_NAME) && !it.startsWith(KOTLIN_TEST_MODULE_NAME) }
|
||||
JUnit4Assertions.assertSameElements(got, expectedRebuilt) {
|
||||
"Mismatched rebuilt modules at step $stepId"
|
||||
}
|
||||
@@ -388,7 +390,7 @@ abstract class AbstractInvalidationTest(
|
||||
|
||||
val cacheUpdater = CacheUpdater(
|
||||
mainModule = mainModuleInfo.modulePath,
|
||||
allModules = testInfo.mapTo(mutableListOf(STDLIB_KLIB)) { it.modulePath },
|
||||
allModules = testInfo.mapTo(mutableListOf(STDLIB_KLIB, KOTLIN_TEST_KLIB)) { it.modulePath },
|
||||
mainModuleFriends = mainModuleInfo.friends,
|
||||
cacheDir = buildDir.resolve("incremental-cache").absolutePath,
|
||||
compilerConfiguration = configuration,
|
||||
|
||||
Generated
+6
@@ -349,6 +349,12 @@ public class JsFirInvalidationPerFileTestGenerated extends AbstractJsFirInvalida
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsModuleAnnotationOnObjectWithUsage/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinTest")
|
||||
public void testKotlinTest() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/kotlinTest/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("languageVersionSettings")
|
||||
public void testLanguageVersionSettings() throws Exception {
|
||||
|
||||
Generated
+6
@@ -349,6 +349,12 @@ public class JsFirInvalidationPerModuleTestGenerated extends AbstractJsFirInvali
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsModuleAnnotationOnObjectWithUsage/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinTest")
|
||||
public void testKotlinTest() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/kotlinTest/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("languageVersionSettings")
|
||||
public void testLanguageVersionSettings() throws Exception {
|
||||
|
||||
Generated
+6
@@ -349,6 +349,12 @@ public class JsIrES6InvalidationPerFileTestGenerated extends AbstractJsIrES6Inva
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsModuleAnnotationOnObjectWithUsage/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinTest")
|
||||
public void testKotlinTest() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/kotlinTest/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("languageVersionSettings")
|
||||
public void testLanguageVersionSettings() throws Exception {
|
||||
|
||||
+6
@@ -349,6 +349,12 @@ public class JsIrES6InvalidationPerModuleTestGenerated extends AbstractJsIrES6In
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsModuleAnnotationOnObjectWithUsage/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinTest")
|
||||
public void testKotlinTest() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/kotlinTest/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("languageVersionSettings")
|
||||
public void testLanguageVersionSettings() throws Exception {
|
||||
|
||||
Generated
+6
@@ -349,6 +349,12 @@ public class JsIrInvalidationPerFileTestGenerated extends AbstractJsIrInvalidati
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsModuleAnnotationOnObjectWithUsage/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinTest")
|
||||
public void testKotlinTest() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/kotlinTest/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("languageVersionSettings")
|
||||
public void testLanguageVersionSettings() throws Exception {
|
||||
|
||||
Generated
+6
@@ -349,6 +349,12 @@ public class JsIrInvalidationPerModuleTestGenerated extends AbstractJsIrInvalida
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsModuleAnnotationOnObjectWithUsage/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinTest")
|
||||
public void testKotlinTest() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/kotlinTest/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("languageVersionSettings")
|
||||
public void testLanguageVersionSettings() throws Exception {
|
||||
|
||||
+64
@@ -2616,6 +2616,70 @@ public class FirJsBoxTestGenerated extends AbstractFirJsBoxTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("js/js.translator/testData/box/esModules/kotlin.test")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Kotlin_test {
|
||||
@Test
|
||||
public void testAllFilesPresentInKotlin_test() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/esModules/kotlin.test"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("beforeAfter.kt")
|
||||
public void testBeforeAfter() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/beforeAfter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ignore.kt")
|
||||
public void testIgnore() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/ignore.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("illegalParameters.kt")
|
||||
public void testIllegalParameters() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/illegalParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("incremental.kt")
|
||||
public void testIncremental() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/incremental.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inherited.kt")
|
||||
public void testInherited() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/inherited.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("mpp.kt")
|
||||
public void testMpp() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/mpp.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nested.kt")
|
||||
public void testNested() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/nested.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("returnTestResult.kt")
|
||||
public void testReturnTestResult() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/returnTestResult.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/simple.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("js/js.translator/testData/box/esModules/main")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+64
@@ -2722,6 +2722,70 @@ public class FirJsES6BoxTestGenerated extends AbstractFirJsES6BoxTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("js/js.translator/testData/box/esModules/kotlin.test")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Kotlin_test {
|
||||
@Test
|
||||
public void testAllFilesPresentInKotlin_test() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/esModules/kotlin.test"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("beforeAfter.kt")
|
||||
public void testBeforeAfter() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/beforeAfter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ignore.kt")
|
||||
public void testIgnore() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/ignore.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("illegalParameters.kt")
|
||||
public void testIllegalParameters() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/illegalParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("incremental.kt")
|
||||
public void testIncremental() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/incremental.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inherited.kt")
|
||||
public void testInherited() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/inherited.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("mpp.kt")
|
||||
public void testMpp() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/mpp.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nested.kt")
|
||||
public void testNested() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/nested.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("returnTestResult.kt")
|
||||
public void testReturnTestResult() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/returnTestResult.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/simple.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("js/js.translator/testData/box/esModules/main")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+64
@@ -2722,6 +2722,70 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test {
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("js/js.translator/testData/box/esModules/kotlin.test")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Kotlin_test {
|
||||
@Test
|
||||
public void testAllFilesPresentInKotlin_test() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/esModules/kotlin.test"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("beforeAfter.kt")
|
||||
public void testBeforeAfter() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/beforeAfter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ignore.kt")
|
||||
public void testIgnore() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/ignore.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("illegalParameters.kt")
|
||||
public void testIllegalParameters() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/illegalParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("incremental.kt")
|
||||
public void testIncremental() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/incremental.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inherited.kt")
|
||||
public void testInherited() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/inherited.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("mpp.kt")
|
||||
public void testMpp() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/mpp.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nested.kt")
|
||||
public void testNested() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/nested.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("returnTestResult.kt")
|
||||
public void testReturnTestResult() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/returnTestResult.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/simple.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("js/js.translator/testData/box/esModules/main")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+64
@@ -2616,6 +2616,70 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("js/js.translator/testData/box/esModules/kotlin.test")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Kotlin_test {
|
||||
@Test
|
||||
public void testAllFilesPresentInKotlin_test() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/esModules/kotlin.test"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("beforeAfter.kt")
|
||||
public void testBeforeAfter() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/beforeAfter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ignore.kt")
|
||||
public void testIgnore() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/ignore.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("illegalParameters.kt")
|
||||
public void testIllegalParameters() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/illegalParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("incremental.kt")
|
||||
public void testIncremental() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/incremental.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inherited.kt")
|
||||
public void testInherited() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/inherited.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("mpp.kt")
|
||||
public void testMpp() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/mpp.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nested.kt")
|
||||
public void testNested() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/nested.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("returnTestResult.kt")
|
||||
public void testReturnTestResult() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/returnTestResult.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/simple.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("js/js.translator/testData/box/esModules/main")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
package common
|
||||
|
||||
import kotlin.test.FrameworkAdapter
|
||||
import kotlin.collections.*
|
||||
|
||||
private var sortingContext = SortingContext()
|
||||
|
||||
private var bodyContext: TestBodyContext? = null
|
||||
|
||||
fun call(name: String) = bodyContext!!.call(name)
|
||||
|
||||
fun raise(name: String): Nothing {
|
||||
bodyContext!!.raised(name)
|
||||
throw Exception(name)
|
||||
}
|
||||
|
||||
// Adapter should be initialized eagerly
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
@EagerInitialization
|
||||
private val underscore = kotlin.test.setAdapter(object : FrameworkAdapter {
|
||||
override fun suite(name: String, ignored: Boolean, suiteFn: () -> Unit) {
|
||||
sortingContext.suite(name, ignored) { suiteFn() }
|
||||
}
|
||||
|
||||
override fun test(name: String, ignored: Boolean, testFn: () -> Any?) {
|
||||
sortingContext.test(name, ignored) { returned(testFn()) }
|
||||
}
|
||||
})
|
||||
|
||||
interface SuiteContext {
|
||||
fun suite(name: String, ignored: Boolean = false, body: SuiteContext.() -> Unit)
|
||||
|
||||
fun test(name: String, ignored: Boolean = false, body: TestBodyContext.() -> Unit = {})
|
||||
}
|
||||
|
||||
|
||||
interface TestBodyContext {
|
||||
fun call(name: String)
|
||||
|
||||
fun raised(msg: String)
|
||||
|
||||
fun caught(msg: String)
|
||||
|
||||
fun returned(msg: Any?)
|
||||
}
|
||||
|
||||
private sealed class Entity(val name: String,
|
||||
val ignored: Boolean)
|
||||
|
||||
private class Suite(name: String, ignored: Boolean, val body: SuiteContext.() -> Unit): Entity(name, ignored)
|
||||
|
||||
private class Test(name: String, ignored: Boolean, val body: TestBodyContext.() -> Unit): Entity(name, ignored)
|
||||
|
||||
|
||||
private class SortingContext: SuiteContext {
|
||||
|
||||
val structure = mutableListOf<Entity>()
|
||||
|
||||
override fun suite(name: String, ignored: Boolean, body: SuiteContext.() -> Unit) {
|
||||
structure += Suite(name, ignored, body)
|
||||
}
|
||||
|
||||
override fun test(name: String, ignored: Boolean, body: TestBodyContext.() -> Unit) {
|
||||
structure += Test(name, ignored, body)
|
||||
}
|
||||
|
||||
fun <T: SuiteContext> replayInto(context: T): T {
|
||||
structure.sortedBy { it.name }.forEach {
|
||||
when (it) {
|
||||
is Suite -> context.suite(it.name, it.ignored) {
|
||||
val oldSorter = sortingContext
|
||||
|
||||
sortingContext = SortingContext()
|
||||
it.body(sortingContext)
|
||||
sortingContext.replayInto(this)
|
||||
|
||||
sortingContext = oldSorter
|
||||
}
|
||||
is Test -> context.test(it.name, it.ignored) {
|
||||
bodyContext = this
|
||||
it.body(this)
|
||||
bodyContext = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
}
|
||||
|
||||
private class LoggingContext : SuiteContext, TestBodyContext{
|
||||
val log: String
|
||||
get() = logHead + (lastRecord ?: "")
|
||||
|
||||
private var indentation = ""
|
||||
|
||||
override fun suite(name: String, ignored: Boolean, body: SuiteContext.() -> Unit) = indent {
|
||||
record("suite(\"$name\"${optionalIgnore(ignored)}) {")
|
||||
runSafely { this.body() }
|
||||
record("}")
|
||||
}
|
||||
|
||||
override fun test(name: String, ignored: Boolean, body: TestBodyContext.() -> Unit) = indent {
|
||||
val num = record("test(\"$name\"${optionalIgnore(ignored)}) {")
|
||||
|
||||
runSafely { this.body() }
|
||||
|
||||
if (!writtenSince(num)) {
|
||||
record("test(\"$name\"${optionalIgnore(ignored)})", replaceLast = true)
|
||||
}
|
||||
else {
|
||||
record("}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun call(name: String) = indent {
|
||||
record("call(\"$name\")")
|
||||
}
|
||||
|
||||
override fun raised(msg: String) = indent {
|
||||
record("raised(\"$msg\")")
|
||||
}
|
||||
|
||||
override fun caught(msg: String) = indent {
|
||||
record("caught(\"$msg\")")
|
||||
}
|
||||
|
||||
override fun returned(msg: Any?) = indent {
|
||||
if (msg is String) record("returned(\"$msg\")")
|
||||
}
|
||||
|
||||
private fun runSafely(body: () -> Unit) {
|
||||
try {
|
||||
body()
|
||||
}
|
||||
catch (t: Throwable) {
|
||||
caught(t.message ?: "")
|
||||
}
|
||||
}
|
||||
|
||||
private fun indent(body: () -> Unit) {
|
||||
val prevIndentation = indentation
|
||||
indentation += " "
|
||||
body()
|
||||
indentation = prevIndentation
|
||||
}
|
||||
|
||||
|
||||
private var logHead: String = ""
|
||||
private var lastRecord: String? = null
|
||||
private var counter = 0
|
||||
|
||||
private fun writtenSince(num: Int) = counter > num
|
||||
|
||||
private fun record(s: String, replaceLast: Boolean = false): Int {
|
||||
if (!replaceLast && lastRecord != null) {
|
||||
logHead += lastRecord
|
||||
}
|
||||
|
||||
lastRecord = indentation + s + "\n"
|
||||
|
||||
return ++counter
|
||||
}
|
||||
|
||||
private fun optionalIgnore(ignored: Boolean) = if (ignored) ", true" else ""
|
||||
}
|
||||
|
||||
fun checkLog(wrapInEmptySuite: Boolean = true, body: SuiteContext.() -> Unit): String {
|
||||
val expectedContext = SortingContext()
|
||||
if (wrapInEmptySuite) {
|
||||
expectedContext.suite("") {
|
||||
body()
|
||||
}
|
||||
} else {
|
||||
expectedContext.body()
|
||||
}
|
||||
|
||||
val expectedLog = expectedContext.replayInto(LoggingContext()).log
|
||||
val actualLog = sortingContext.replayInto(LoggingContext()).log
|
||||
|
||||
if (actualLog != expectedLog) {
|
||||
return "Failed test structure check. Expected: \"${expectedLog}\"; actual: \"${actualLog}\"."
|
||||
}
|
||||
else {
|
||||
return "OK"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1706
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
// SKIP_DCE_DRIVEN
|
||||
// RUN_UNIT_TESTS
|
||||
// ES_MODULES
|
||||
|
||||
// FILE: test.kt
|
||||
import common.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.BeforeTest
|
||||
import kotlin.test.AfterTest
|
||||
|
||||
class Simple {
|
||||
@BeforeTest
|
||||
fun before() {
|
||||
call("before")
|
||||
}
|
||||
|
||||
@AfterTest
|
||||
fun after() {
|
||||
call("after")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun foo() {
|
||||
call("foo")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun bar() {
|
||||
call("bar")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun withException() {
|
||||
call("withException")
|
||||
raise("some exception")
|
||||
call("never happens")
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: box.kt
|
||||
import common.*
|
||||
|
||||
fun box() = checkLog {
|
||||
suite("Simple") {
|
||||
test("foo") {
|
||||
call("before")
|
||||
call("foo")
|
||||
call("after")
|
||||
}
|
||||
test("bar") {
|
||||
call("before")
|
||||
call("bar")
|
||||
call("after")
|
||||
}
|
||||
test("withException") {
|
||||
call("before")
|
||||
call("withException")
|
||||
raised("some exception")
|
||||
call("after")
|
||||
caught("some exception")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1709
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
// SKIP_DCE_DRIVEN
|
||||
// RUN_UNIT_TESTS
|
||||
// ES_MODULES
|
||||
|
||||
// FILE: test.kt
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.Ignore
|
||||
|
||||
class A {
|
||||
@Test
|
||||
fun foo() {
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
fun bar() {
|
||||
}
|
||||
|
||||
@Ignore
|
||||
class B {
|
||||
@Test
|
||||
fun foo() {
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
fun bar() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore
|
||||
class C {
|
||||
@Test
|
||||
fun foo() {
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
fun bar() {
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: box.kt
|
||||
import common.*
|
||||
|
||||
fun box() = checkLog {
|
||||
suite("A") {
|
||||
test("foo")
|
||||
test("bar", true)
|
||||
suite("B", true) {
|
||||
test("foo")
|
||||
test("bar", true)
|
||||
}
|
||||
}
|
||||
suite("C", true) {
|
||||
test("foo")
|
||||
test("bar", true)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
// IGNORE_BACKEND: JS
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
// SKIP_DCE_DRIVEN
|
||||
// RUN_UNIT_TESTS
|
||||
// ES_MODULES
|
||||
|
||||
// FILE: test.kt
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class BadClass(id: Int) {
|
||||
@Test
|
||||
fun foo() {}
|
||||
}
|
||||
|
||||
private class BadPrivateClass {
|
||||
@Test
|
||||
fun foo() {}
|
||||
}
|
||||
|
||||
class BadProtectedMethodClass {
|
||||
@Test
|
||||
protected fun foo() {}
|
||||
}
|
||||
|
||||
class BadPrimaryGoodSecondary(private val id: Int) {
|
||||
constructor(): this(3)
|
||||
@Test
|
||||
fun foo() {
|
||||
assertEquals(id, 3)
|
||||
}
|
||||
}
|
||||
|
||||
class GoodSecondaryOnly {
|
||||
constructor() {
|
||||
triggered = 3
|
||||
}
|
||||
constructor(id: Int) {
|
||||
triggered = id
|
||||
}
|
||||
companion object {
|
||||
private var triggered = 0
|
||||
}
|
||||
@Test
|
||||
fun foo() {
|
||||
assertEquals(triggered, 3)
|
||||
}
|
||||
}
|
||||
|
||||
class BadSecondaryOnly {
|
||||
private constructor() {}
|
||||
constructor(id: Int) {}
|
||||
@Test
|
||||
fun foo() {}
|
||||
}
|
||||
|
||||
class BadConstructorClass private constructor() {
|
||||
@Test
|
||||
fun foo() {}
|
||||
}
|
||||
|
||||
class BadProtectedConstructorClass protected constructor() {
|
||||
constructor(flag: Boolean): this()
|
||||
@Test
|
||||
fun foo() {}
|
||||
}
|
||||
|
||||
class GoodClass() {
|
||||
constructor(id: Int): this()
|
||||
@Test
|
||||
fun foo() {}
|
||||
}
|
||||
|
||||
class GoodNestedClass {
|
||||
class NestedTestClass {
|
||||
@Test
|
||||
fun foo() {}
|
||||
|
||||
fun helperMethod(param: String) {}
|
||||
}
|
||||
}
|
||||
|
||||
class BadNestedClass {
|
||||
class NestedTestClass(id: Int) {
|
||||
@Test
|
||||
fun foo() {}
|
||||
}
|
||||
}
|
||||
|
||||
class BadMethodClass() {
|
||||
@Test
|
||||
fun foo(id: Int) {}
|
||||
|
||||
@Test
|
||||
private fun ping() {}
|
||||
}
|
||||
|
||||
// non-reachable scenarios are tested in nested.kt
|
||||
class OuterWithPrivateCompanion {
|
||||
private companion object {
|
||||
object InnerCompanion {
|
||||
@Test
|
||||
fun innerCompanionTest() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class OuterWithPrivateMethod {
|
||||
companion object {
|
||||
object InnerCompanion {
|
||||
@Test
|
||||
private fun innerCompanionTest() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: box.kt
|
||||
import common.*
|
||||
|
||||
fun box() = checkLog {
|
||||
suite("BadClass") {
|
||||
test("foo") {
|
||||
caught("Test class BadClass must declare a public or internal constructor with no explicit parameters")
|
||||
}
|
||||
}
|
||||
suite("BadPrivateClass") {
|
||||
test("foo") {
|
||||
caught("Test method BadPrivateClass::foo should have public or internal visibility, can not have parameters")
|
||||
}
|
||||
}
|
||||
suite("BadProtectedMethodClass") {
|
||||
test("foo") {
|
||||
caught("Test method BadProtectedMethodClass::foo should have public or internal visibility, can not have parameters")
|
||||
}
|
||||
}
|
||||
suite("BadPrimaryGoodSecondary") {
|
||||
test("foo")
|
||||
}
|
||||
suite("GoodSecondaryOnly") {
|
||||
test("foo")
|
||||
}
|
||||
suite("BadSecondaryOnly") {
|
||||
test("foo") {
|
||||
caught("Test class BadSecondaryOnly must declare a public or internal constructor with no explicit parameters")
|
||||
}
|
||||
}
|
||||
suite("BadConstructorClass") {
|
||||
test("foo") {
|
||||
caught("Test class BadConstructorClass must declare a public or internal constructor with no explicit parameters")
|
||||
}
|
||||
}
|
||||
suite("BadProtectedConstructorClass") {
|
||||
test("foo") {
|
||||
caught("Test class BadProtectedConstructorClass must declare a public or internal constructor with no explicit parameters")
|
||||
}
|
||||
}
|
||||
suite("GoodClass") {
|
||||
test("foo")
|
||||
}
|
||||
suite("GoodNestedClass") {
|
||||
suite("NestedTestClass") {
|
||||
test("foo")
|
||||
}
|
||||
}
|
||||
suite("BadNestedClass") {
|
||||
suite("NestedTestClass") {
|
||||
test("foo") {
|
||||
caught("Test class BadNestedClass.NestedTestClass must declare a public or internal constructor with no explicit parameters")
|
||||
}
|
||||
}
|
||||
}
|
||||
suite("BadMethodClass") {
|
||||
test("foo") {
|
||||
caught("Test method BadMethodClass::foo should have public or internal visibility, can not have parameters")
|
||||
}
|
||||
test("ping") {
|
||||
caught("Test method BadMethodClass::ping should have public or internal visibility, can not have parameters")
|
||||
}
|
||||
}
|
||||
suite("OuterWithPrivateCompanion") {
|
||||
suite("Companion") {
|
||||
suite("InnerCompanion") {
|
||||
test("innerCompanionTest") {
|
||||
caught("Test method OuterWithPrivateCompanion.Companion.InnerCompanion::innerCompanionTest should have public or internal visibility, can not have parameters")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
suite("OuterWithPrivateMethod") {
|
||||
suite("Companion") {
|
||||
suite("InnerCompanion") {
|
||||
test("innerCompanionTest") {
|
||||
caught("Test method OuterWithPrivateMethod.Companion.InnerCompanion::innerCompanionTest should have public or internal visibility, can not have parameters")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1829
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
// SKIP_DCE_DRIVEN
|
||||
// RUN_UNIT_TESTS
|
||||
// ES_MODULES
|
||||
|
||||
// FILE: a.kt
|
||||
package a
|
||||
|
||||
import common.*
|
||||
import kotlin.test.*
|
||||
|
||||
class A {
|
||||
@BeforeTest
|
||||
fun before() {
|
||||
call("a.A.before")
|
||||
}
|
||||
|
||||
@AfterTest
|
||||
fun after() {
|
||||
call("a.A.after")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun passing() {
|
||||
call("a.A.passing")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun failing() {
|
||||
call("a.A.failing")
|
||||
raise("a.A.failing.exception")
|
||||
call("never happens")
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
fun ignored() {
|
||||
call("a.A.ignored")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun withException() {
|
||||
call("withException")
|
||||
raise("some exception")
|
||||
call("never happens")
|
||||
}
|
||||
|
||||
inner class Inner {
|
||||
@Test
|
||||
fun innerTest() {
|
||||
call("a.A.Inner.innerTest")
|
||||
}
|
||||
}
|
||||
|
||||
class Nested {
|
||||
@Test
|
||||
fun nestedTest() {
|
||||
call("a.A.Nested.nestedTest")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@Test
|
||||
fun companionTest() {
|
||||
call("a.A.companionTest")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
object O {
|
||||
@Test
|
||||
fun test() {
|
||||
call("a.O.test")
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: a_a.kt
|
||||
package a.a
|
||||
|
||||
import common.*
|
||||
import kotlin.test.*
|
||||
|
||||
class A {
|
||||
@BeforeTest
|
||||
fun before() {
|
||||
call("a.a.A.before")
|
||||
}
|
||||
|
||||
@AfterTest
|
||||
fun after() {
|
||||
call("a.a.A.after")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun passing() {
|
||||
call("a.a.A.passing")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun failing() {
|
||||
call("a.a.A.failing")
|
||||
raise("a.a.A.failing.exception")
|
||||
call("never happens")
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
fun ignored() {
|
||||
call("a.a.A.ignored")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun withException() {
|
||||
call("withException")
|
||||
raise("some exception")
|
||||
call("never happens")
|
||||
}
|
||||
|
||||
inner class Inner {
|
||||
@Test
|
||||
fun innerTest() {
|
||||
call("a.a.A.Inner.innerTest")
|
||||
}
|
||||
}
|
||||
|
||||
class Nested {
|
||||
@Test
|
||||
fun nestedTest() {
|
||||
call("a.a.A.Nested.nestedTest")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@Test
|
||||
fun companionTest() {
|
||||
call("a.a.A.companionTest")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object O {
|
||||
@Test
|
||||
fun test() {
|
||||
call("a.a.O.test")
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: a_a2.kt
|
||||
// RECOMPILE
|
||||
package a.a
|
||||
|
||||
import common.*
|
||||
import kotlin.test.*
|
||||
|
||||
class B {
|
||||
@BeforeTest
|
||||
fun before() {
|
||||
call("a.a.B.before")
|
||||
}
|
||||
|
||||
@AfterTest
|
||||
fun after() {
|
||||
call("a.a.B.after")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun passing() {
|
||||
call("a.a.B.passing")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun failing() {
|
||||
call("a.a.B.failing")
|
||||
raise("a.a.B.failing.exception")
|
||||
call("never happens")
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
fun ignored() {
|
||||
call("a.a.B.ignored")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun withException() {
|
||||
call("withException")
|
||||
raise("some exception")
|
||||
call("never happens")
|
||||
}
|
||||
|
||||
inner class Inner {
|
||||
@Test
|
||||
fun innerTest() {
|
||||
call("a.a.B.Inner.innerTest")
|
||||
}
|
||||
}
|
||||
|
||||
class Nested {
|
||||
@Test
|
||||
fun nestedTest() {
|
||||
call("a.a.B.Nested.nestedTest")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@Test
|
||||
fun companionTest() {
|
||||
call("a.a.B.companionTest")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
object O2 {
|
||||
@Test
|
||||
fun test() {
|
||||
call("a.a.O2.test")
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
|
||||
import common.*
|
||||
import kotlin.test.Test
|
||||
|
||||
class Simple {
|
||||
@Test fun foo() {
|
||||
call("foo")
|
||||
}
|
||||
}
|
||||
|
||||
fun box() = checkLog(false) {
|
||||
suite("a") {
|
||||
suite("A") {
|
||||
test("passing") {
|
||||
call("a.A.before")
|
||||
call("a.A.passing")
|
||||
call("a.A.after")
|
||||
}
|
||||
test("failing") {
|
||||
call("a.A.before")
|
||||
call("a.A.failing")
|
||||
raised("a.A.failing.exception")
|
||||
call("a.A.after")
|
||||
caught("a.A.failing.exception")
|
||||
}
|
||||
test("ignored", true) {
|
||||
call("a.A.before")
|
||||
call("a.A.ignored")
|
||||
call("a.A.after")
|
||||
}
|
||||
test("withException") {
|
||||
call("a.A.before")
|
||||
call("withException")
|
||||
raised("some exception")
|
||||
call("a.A.after")
|
||||
caught("some exception")
|
||||
}
|
||||
suite("Inner") {
|
||||
test("innerTest") {
|
||||
call("a.A.Inner.innerTest")
|
||||
}
|
||||
}
|
||||
suite("Nested") {
|
||||
test("nestedTest") {
|
||||
call("a.A.Nested.nestedTest")
|
||||
}
|
||||
}
|
||||
suite("Companion") {
|
||||
test("companionTest") {
|
||||
call("a.A.companionTest")
|
||||
}
|
||||
}
|
||||
}
|
||||
suite("O") {
|
||||
test("test") {
|
||||
call("a.O.test")
|
||||
}
|
||||
}
|
||||
}
|
||||
suite("a.a") {
|
||||
suite("A") {
|
||||
test("passing") {
|
||||
call("a.a.A.before")
|
||||
call("a.a.A.passing")
|
||||
call("a.a.A.after")
|
||||
}
|
||||
test("failing") {
|
||||
call("a.a.A.before")
|
||||
call("a.a.A.failing")
|
||||
raised("a.a.A.failing.exception")
|
||||
call("a.a.A.after")
|
||||
caught("a.a.A.failing.exception")
|
||||
}
|
||||
test("ignored", true) {
|
||||
call("a.a.A.before")
|
||||
call("a.a.A.ignored")
|
||||
call("a.a.A.after")
|
||||
}
|
||||
test("withException") {
|
||||
call("a.a.A.before")
|
||||
call("withException")
|
||||
raised("some exception")
|
||||
call("a.a.A.after")
|
||||
caught("some exception")
|
||||
}
|
||||
suite("Inner") {
|
||||
test("innerTest") {
|
||||
call("a.a.A.Inner.innerTest")
|
||||
}
|
||||
}
|
||||
suite("Nested") {
|
||||
test("nestedTest") {
|
||||
call("a.a.A.Nested.nestedTest")
|
||||
}
|
||||
}
|
||||
suite("Companion") {
|
||||
test("companionTest") {
|
||||
call("a.a.A.companionTest")
|
||||
}
|
||||
}
|
||||
}
|
||||
suite("O") {
|
||||
test("test") {
|
||||
call("a.a.O.test")
|
||||
}
|
||||
}
|
||||
suite("B") {
|
||||
test("passing") {
|
||||
call("a.a.B.before")
|
||||
call("a.a.B.passing")
|
||||
call("a.a.B.after")
|
||||
}
|
||||
test("failing") {
|
||||
call("a.a.B.before")
|
||||
call("a.a.B.failing")
|
||||
raised("a.a.B.failing.exception")
|
||||
call("a.a.B.after")
|
||||
caught("a.a.B.failing.exception")
|
||||
}
|
||||
test("ignored", true) {
|
||||
call("a.a.B.before")
|
||||
call("a.a.B.ignored")
|
||||
call("a.a.B.after")
|
||||
}
|
||||
test("withException") {
|
||||
call("a.a.B.before")
|
||||
call("withException")
|
||||
raised("some exception")
|
||||
call("a.a.B.after")
|
||||
caught("some exception")
|
||||
}
|
||||
suite("Inner") {
|
||||
test("innerTest") {
|
||||
call("a.a.B.Inner.innerTest")
|
||||
}
|
||||
}
|
||||
suite("Nested") {
|
||||
test("nestedTest") {
|
||||
call("a.a.B.Nested.nestedTest")
|
||||
}
|
||||
}
|
||||
suite("Companion") {
|
||||
test("companionTest") {
|
||||
call("a.a.B.companionTest")
|
||||
}
|
||||
}
|
||||
}
|
||||
suite("O2") {
|
||||
test("test") {
|
||||
call("a.a.O2.test")
|
||||
}
|
||||
}
|
||||
}
|
||||
suite("") {
|
||||
suite("Simple") {
|
||||
test("foo") {
|
||||
call("foo")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1719
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
// SKIP_DCE_DRIVEN
|
||||
// RUN_UNIT_TESTS
|
||||
// ES_MODULES
|
||||
|
||||
// FILE: test.kt
|
||||
import common.call
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.BeforeTest
|
||||
import kotlin.test.AfterTest
|
||||
|
||||
interface TestyInterface {
|
||||
@Test
|
||||
fun someVarTest() {
|
||||
call("TestyInterface.someVarTest")
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractTest : TestyInterface {
|
||||
@Test abstract fun abstractTest()
|
||||
|
||||
@Test
|
||||
fun someTest() {
|
||||
call("AbstractTest.someTest")
|
||||
}
|
||||
}
|
||||
|
||||
interface BeforeAfterInterface {
|
||||
@BeforeTest
|
||||
@AfterTest
|
||||
fun beforeAfter() {
|
||||
call("beforeAfter")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class InheritedTest : AbstractTest(), BeforeAfterInterface {
|
||||
@Test override fun abstractTest() {
|
||||
call("InheritedTest.abstractTest")
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: box.kt
|
||||
import common.*
|
||||
|
||||
fun box() = checkLog() {
|
||||
suite("InheritedTest") {
|
||||
test("abstractTest") {
|
||||
call("beforeAfter")
|
||||
call("InheritedTest.abstractTest")
|
||||
call("beforeAfter")
|
||||
}
|
||||
test("someTest") {
|
||||
call("beforeAfter")
|
||||
call("AbstractTest.someTest")
|
||||
call("beforeAfter")
|
||||
}
|
||||
test("someVarTest") {
|
||||
call("beforeAfter")
|
||||
call("TestyInterface.someVarTest")
|
||||
call("beforeAfter")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1697
|
||||
// !LANGUAGE: +MultiPlatformProjects
|
||||
// TARGET_FRONTEND: ClassicFrontend
|
||||
// FIR status: expect/actual in one module
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
// SKIP_DCE_DRIVEN
|
||||
// RUN_UNIT_TESTS
|
||||
// ES_MODULES
|
||||
|
||||
// FILE: lib.kt
|
||||
import kotlin.test.Test
|
||||
|
||||
expect class PlatformTest {
|
||||
@Test fun platformTest()
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
import common.*
|
||||
import kotlin.test.Test
|
||||
|
||||
actual class PlatformTest {
|
||||
@Test actual fun platformTest() {}
|
||||
|
||||
@Test fun someOtherTest() {}
|
||||
}
|
||||
|
||||
fun box() = checkLog {
|
||||
suite("PlatformTest") {
|
||||
test("platformTest")
|
||||
test("someOtherTest")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1735
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
// SKIP_DCE_DRIVEN
|
||||
// RUN_UNIT_TESTS
|
||||
// ES_MODULES
|
||||
|
||||
// FILE: test.kt
|
||||
import common.call
|
||||
import kotlin.test.Test
|
||||
|
||||
class Outer {
|
||||
|
||||
val prop = "prop"
|
||||
|
||||
@Test
|
||||
fun test1() {
|
||||
}
|
||||
|
||||
inner class Inner {
|
||||
|
||||
@Test fun innerTest() {
|
||||
call(prop + "Inner")
|
||||
}
|
||||
|
||||
inner class Inneer {
|
||||
@Test fun innermostTest() {
|
||||
call(prop + "Inneer")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Nested {
|
||||
@Test
|
||||
fun a() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun b() {
|
||||
}
|
||||
|
||||
class EvenDeeper {
|
||||
|
||||
@Test
|
||||
fun c() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test2() {
|
||||
}
|
||||
|
||||
companion object {
|
||||
@Test
|
||||
fun companionTest() {
|
||||
}
|
||||
|
||||
object InnerCompanion {
|
||||
@Test
|
||||
fun innerCompanionTest() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: box.kt
|
||||
import common.*
|
||||
|
||||
fun box() = checkLog {
|
||||
suite("Outer") {
|
||||
test("test1")
|
||||
suite("Inner") {
|
||||
test("innerTest") {
|
||||
call("propInner")
|
||||
}
|
||||
suite("Inneer") {
|
||||
test("innermostTest") {
|
||||
call("propInneer")
|
||||
}
|
||||
}
|
||||
}
|
||||
suite("Nested") {
|
||||
test("a")
|
||||
test("b")
|
||||
suite("EvenDeeper") {
|
||||
test("c")
|
||||
}
|
||||
}
|
||||
test("test2")
|
||||
suite("Companion") {
|
||||
test("companionTest")
|
||||
suite("InnerCompanion") {
|
||||
test("innerCompanionTest")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1737
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
// SKIP_DCE_DRIVEN
|
||||
// RUN_UNIT_TESTS
|
||||
// ES_MODULES
|
||||
|
||||
// FILE: test.kt
|
||||
import common.call
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.BeforeTest
|
||||
import kotlin.test.AfterTest
|
||||
|
||||
open class A {
|
||||
@Test fun foo(): String {
|
||||
return "promise"
|
||||
}
|
||||
|
||||
@Test fun bar() = "future"
|
||||
}
|
||||
|
||||
interface WithBefore {
|
||||
@BeforeTest fun before() {
|
||||
call("before")
|
||||
}
|
||||
}
|
||||
|
||||
interface WithAfter {
|
||||
@AfterTest fun after() {
|
||||
call("after")
|
||||
}
|
||||
}
|
||||
|
||||
class B: A(), WithBefore
|
||||
|
||||
class C: A(), WithAfter
|
||||
|
||||
class D: A(), WithBefore, WithAfter
|
||||
|
||||
// FILE: box.kt
|
||||
import common.*
|
||||
|
||||
fun box() = checkLog {
|
||||
suite("A") {
|
||||
test("foo") {
|
||||
returned("promise")
|
||||
}
|
||||
test("bar") {
|
||||
returned("future")
|
||||
}
|
||||
}
|
||||
suite("B") {
|
||||
test("foo") {
|
||||
call("before")
|
||||
returned("promise")
|
||||
}
|
||||
test("bar") {
|
||||
call("before")
|
||||
returned("future")
|
||||
}
|
||||
}
|
||||
suite("C") {
|
||||
test("foo") {
|
||||
call("after")
|
||||
returned("promise")
|
||||
}
|
||||
test("bar") {
|
||||
call("after")
|
||||
returned("future")
|
||||
}
|
||||
}
|
||||
suite("D") {
|
||||
test("foo") {
|
||||
call("before")
|
||||
call("after")
|
||||
returned("promise")
|
||||
}
|
||||
test("bar") {
|
||||
call("before")
|
||||
call("after")
|
||||
returned("future")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1698
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
// SKIP_DCE_DRIVEN
|
||||
// RUN_UNIT_TESTS
|
||||
// ES_MODULES
|
||||
|
||||
// FILE: test.kt
|
||||
import common.call
|
||||
import kotlin.test.Test
|
||||
|
||||
class Simple {
|
||||
@Test fun foo() {
|
||||
call("foo")
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: box.kt
|
||||
import common.*
|
||||
|
||||
fun box() = checkLog {
|
||||
suite("Simple") {
|
||||
test("foo") {
|
||||
call("foo")
|
||||
}
|
||||
}
|
||||
}
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
import kotlin.test.FrameworkAdapter
|
||||
import kotlin.collections.*
|
||||
|
||||
private var sortingContext = SortingContext()
|
||||
|
||||
private var bodyContext: TestBodyContext? = null
|
||||
|
||||
fun call(name: String) = bodyContext!!.call(name)
|
||||
|
||||
fun raise(name: String): Nothing {
|
||||
bodyContext!!.raised(name)
|
||||
throw Exception(name)
|
||||
}
|
||||
|
||||
// Adapter should be initialized eagerly
|
||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "DEPRECATION")
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
@EagerInitialization
|
||||
private val underscore = kotlin.test.setAdapter(object : FrameworkAdapter {
|
||||
override fun suite(name: String, ignored: Boolean, suiteFn: () -> Unit) {
|
||||
sortingContext.suite(name, ignored) { suiteFn() }
|
||||
}
|
||||
|
||||
override fun test(name: String, ignored: Boolean, testFn: () -> Any?) {
|
||||
sortingContext.test(name, ignored) { returned(testFn()) }
|
||||
}
|
||||
})
|
||||
|
||||
interface SuiteContext {
|
||||
fun suite(name: String, ignored: Boolean = false, body: SuiteContext.() -> Unit)
|
||||
|
||||
fun test(name: String, ignored: Boolean = false, body: TestBodyContext.() -> Unit = {})
|
||||
}
|
||||
|
||||
|
||||
interface TestBodyContext {
|
||||
fun call(name: String)
|
||||
|
||||
fun raised(msg: String)
|
||||
|
||||
fun caught(msg: String)
|
||||
|
||||
fun returned(msg: Any?)
|
||||
}
|
||||
|
||||
private sealed class Entity(val name: String,
|
||||
val ignored: Boolean)
|
||||
|
||||
private class Suite(name: String, ignored: Boolean, val body: SuiteContext.() -> Unit): Entity(name, ignored)
|
||||
|
||||
private class Test(name: String, ignored: Boolean, val body: TestBodyContext.() -> Unit): Entity(name, ignored)
|
||||
|
||||
|
||||
private class SortingContext: SuiteContext {
|
||||
|
||||
val structure = mutableListOf<Entity>()
|
||||
|
||||
override fun suite(name: String, ignored: Boolean, body: SuiteContext.() -> Unit) {
|
||||
structure += Suite(name, ignored, body)
|
||||
}
|
||||
|
||||
override fun test(name: String, ignored: Boolean, body: TestBodyContext.() -> Unit) {
|
||||
structure += Test(name, ignored, body)
|
||||
}
|
||||
|
||||
fun <T: SuiteContext> replayInto(context: T): T {
|
||||
structure.sortedBy { it.name }.forEach {
|
||||
when (it) {
|
||||
is Suite -> context.suite(it.name, it.ignored) {
|
||||
val oldSorter = sortingContext
|
||||
|
||||
sortingContext = SortingContext()
|
||||
it.body(sortingContext)
|
||||
sortingContext.replayInto(this)
|
||||
|
||||
sortingContext = oldSorter
|
||||
}
|
||||
is Test -> context.test(it.name, it.ignored) {
|
||||
bodyContext = this
|
||||
it.body(this)
|
||||
bodyContext = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
}
|
||||
|
||||
private class LoggingContext : SuiteContext, TestBodyContext{
|
||||
val log: String
|
||||
get() = logHead + (lastRecord ?: "")
|
||||
|
||||
private var indentation = ""
|
||||
|
||||
override fun suite(name: String, ignored: Boolean, body: SuiteContext.() -> Unit) = indent {
|
||||
record("suite(\"$name\"${optionalIgnore(ignored)}) {")
|
||||
runSafely { this.body() }
|
||||
record("}")
|
||||
}
|
||||
|
||||
override fun test(name: String, ignored: Boolean, body: TestBodyContext.() -> Unit) = indent {
|
||||
val num = record("test(\"$name\"${optionalIgnore(ignored)}) {")
|
||||
|
||||
runSafely { this.body() }
|
||||
|
||||
if (!writtenSince(num)) {
|
||||
record("test(\"$name\"${optionalIgnore(ignored)})", replaceLast = true)
|
||||
}
|
||||
else {
|
||||
record("}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun call(name: String) = indent {
|
||||
record("call(\"$name\")")
|
||||
}
|
||||
|
||||
override fun raised(msg: String) = indent {
|
||||
record("raised(\"$msg\")")
|
||||
}
|
||||
|
||||
override fun caught(msg: String) = indent {
|
||||
record("caught(\"$msg\")")
|
||||
}
|
||||
|
||||
override fun returned(msg: Any?) = indent {
|
||||
if (msg is String) record("returned(\"$msg\")")
|
||||
}
|
||||
|
||||
private fun runSafely(body: () -> Unit) {
|
||||
try {
|
||||
body()
|
||||
}
|
||||
catch (t: Throwable) {
|
||||
caught(t.message ?: "")
|
||||
}
|
||||
}
|
||||
|
||||
private fun indent(body: () -> Unit) {
|
||||
val prevIndentation = indentation
|
||||
indentation += " "
|
||||
body()
|
||||
indentation = prevIndentation
|
||||
}
|
||||
|
||||
|
||||
private var logHead: String = ""
|
||||
private var lastRecord: String? = null
|
||||
private var counter = 0
|
||||
|
||||
private fun writtenSince(num: Int) = counter > num
|
||||
|
||||
private fun record(s: String, replaceLast: Boolean = false): Int {
|
||||
if (!replaceLast && lastRecord != null) {
|
||||
logHead += lastRecord
|
||||
}
|
||||
|
||||
lastRecord = indentation + s + "\n"
|
||||
|
||||
return ++counter
|
||||
}
|
||||
|
||||
private fun optionalIgnore(ignored: Boolean) = if (ignored) ", true" else ""
|
||||
}
|
||||
|
||||
fun checkLog(wrapInEmptySuite: Boolean = true, body: SuiteContext.() -> Unit): String {
|
||||
val expectedContext = SortingContext()
|
||||
if (wrapInEmptySuite) {
|
||||
expectedContext.suite("") {
|
||||
body()
|
||||
}
|
||||
} else {
|
||||
expectedContext.body()
|
||||
}
|
||||
|
||||
val expectedLog = expectedContext.replayInto(LoggingContext()).log
|
||||
val actualLog = sortingContext.replayInto(LoggingContext()).log
|
||||
|
||||
if (actualLog != expectedLog) {
|
||||
return "Failed test structure check. Expected: \"${expectedLog}\"; actual: \"${actualLog}\"."
|
||||
}
|
||||
else {
|
||||
return "OK"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
fun box(stepId: Int) = when (stepId) {
|
||||
0 -> "OK"
|
||||
1 -> checkLog {
|
||||
suite("Test1") {
|
||||
test("foo") {
|
||||
call("before")
|
||||
call("foo")
|
||||
call("after")
|
||||
}
|
||||
}
|
||||
}
|
||||
2 -> checkLog {
|
||||
suite("Test1") {
|
||||
test("foo") {
|
||||
call("before")
|
||||
call("foo")
|
||||
call("after")
|
||||
}
|
||||
test("withException") {
|
||||
call("before")
|
||||
call("withException")
|
||||
raised("some exception")
|
||||
call("after")
|
||||
caught("some exception")
|
||||
}
|
||||
}
|
||||
}
|
||||
3 -> checkLog {
|
||||
suite("Test1") {
|
||||
test("foo") {
|
||||
call("before")
|
||||
call("foo")
|
||||
call("after")
|
||||
}
|
||||
test("withException") {
|
||||
call("before")
|
||||
call("withException")
|
||||
raised("some exception")
|
||||
call("after")
|
||||
caught("some exception")
|
||||
}
|
||||
}
|
||||
suite("Test2") {
|
||||
test("foo") {
|
||||
call("before")
|
||||
call("foo")
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> "Fail: unexpected step $stepId"
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
STEP 0:
|
||||
added file: m.kt, common.kt
|
||||
STEP 1:
|
||||
modifications:
|
||||
U : test1.1.kt -> test1.kt
|
||||
added file: test1.kt
|
||||
updated exports: common.kt
|
||||
STEP 2:
|
||||
modifications:
|
||||
U : test1.2.kt -> test1.kt
|
||||
modified ir: test1.kt
|
||||
updated exports: common.kt
|
||||
STEP 3:
|
||||
modifications:
|
||||
U : test2.3.kt -> test2.kt
|
||||
added file: test2.kt
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.BeforeTest
|
||||
import kotlin.test.AfterTest
|
||||
|
||||
class Test1 {
|
||||
@BeforeTest
|
||||
fun before() {
|
||||
call("before")
|
||||
}
|
||||
|
||||
@AfterTest
|
||||
fun after() {
|
||||
call("after")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun foo() {
|
||||
call("foo")
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.BeforeTest
|
||||
import kotlin.test.AfterTest
|
||||
|
||||
class Test1 {
|
||||
@BeforeTest
|
||||
fun before() {
|
||||
call("before")
|
||||
}
|
||||
|
||||
@AfterTest
|
||||
fun after() {
|
||||
call("after")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun foo() {
|
||||
call("foo")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun withException() {
|
||||
call("withException")
|
||||
raise("some exception")
|
||||
call("never happens")
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.BeforeTest
|
||||
import kotlin.test.AfterTest
|
||||
|
||||
class Test2 {
|
||||
@BeforeTest
|
||||
fun before() {
|
||||
call("before")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun foo() {
|
||||
call("foo")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
MODULES: main
|
||||
|
||||
STEP 0:
|
||||
libs: main
|
||||
dirty js modules: main
|
||||
dirty js files: main/common, main/m, main/m.export, main
|
||||
STEP 1:
|
||||
libs: main
|
||||
dirty js modules: main
|
||||
dirty js files: main/test1, main/common, main
|
||||
STEP 2:
|
||||
libs: main
|
||||
dirty js modules: main
|
||||
dirty js files: main/test1, main/common
|
||||
STEP 3:
|
||||
libs: main
|
||||
dirty js modules: main
|
||||
dirty js files: main/test2, main
|
||||
@@ -1,3 +1,4 @@
|
||||
import org.gradle.api.tasks.bundling.Jar
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
|
||||
|
||||
plugins {
|
||||
|
||||
@@ -15,6 +15,7 @@ fun Test.useJsIrBoxTests(
|
||||
setupV8()
|
||||
dependsOn(":kotlin-stdlib:jsJar")
|
||||
dependsOn(":kotlin-stdlib:jsJarForTests") // TODO: think how to remove dependency on the artifact in this place
|
||||
dependsOn(":kotlin-test:kotlin-test-js-ir:jsJar")
|
||||
dependsOn(":kotlin-test:kotlin-test-js-ir:compileKotlinJs")
|
||||
dependsOn(":kotlin-stdlib-js-ir-minimal-for-test:compileKotlinJs")
|
||||
dependsOn(":kotlin-dom-api-compat:compileKotlinJs")
|
||||
@@ -24,5 +25,6 @@ fun Test.useJsIrBoxTests(
|
||||
systemProperty("kotlin.js.reduced.stdlib.path", reducedStdlibPath)
|
||||
systemProperty("kotlin.js.kotlin.test.path", kotlinJsTestPath)
|
||||
systemProperty("kotlin.js.stdlib.klib.path", "libraries/stdlib/build/libs/kotlin-stdlib-js-$version.klib")
|
||||
systemProperty("kotlin.js.kotlin.test.klib.path", "libraries/kotlin.test/js-ir/build/libs/kotlin-test-js-$version.klib")
|
||||
systemProperty("kotlin.js.dom.api.compat", domApiCompatPath)
|
||||
}
|
||||
|
||||
Generated
+64
@@ -357,6 +357,70 @@ public class FirWasmJsTranslatorTestGenerated extends AbstractFirWasmJsTranslato
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("js/js.translator/testData/box/esModules/kotlin.test")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Kotlin_test {
|
||||
@Test
|
||||
public void testAllFilesPresentInKotlin_test() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/esModules/kotlin.test"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("beforeAfter.kt")
|
||||
public void testBeforeAfter() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/beforeAfter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ignore.kt")
|
||||
public void testIgnore() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/ignore.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("illegalParameters.kt")
|
||||
public void testIllegalParameters() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/illegalParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("incremental.kt")
|
||||
public void testIncremental() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/incremental.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inherited.kt")
|
||||
public void testInherited() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/inherited.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("mpp.kt")
|
||||
public void testMpp() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/mpp.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nested.kt")
|
||||
public void testNested() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/nested.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("returnTestResult.kt")
|
||||
public void testReturnTestResult() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/returnTestResult.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/simple.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("js/js.translator/testData/box/esModules/main")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
Generated
+64
@@ -357,6 +357,70 @@ public class K1WasmJsTranslatorTestGenerated extends AbstractK1WasmJsTranslatorT
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("js/js.translator/testData/box/esModules/kotlin.test")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Kotlin_test {
|
||||
@Test
|
||||
public void testAllFilesPresentInKotlin_test() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/esModules/kotlin.test"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("beforeAfter.kt")
|
||||
public void testBeforeAfter() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/beforeAfter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ignore.kt")
|
||||
public void testIgnore() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/ignore.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("illegalParameters.kt")
|
||||
public void testIllegalParameters() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/illegalParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("incremental.kt")
|
||||
public void testIncremental() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/incremental.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inherited.kt")
|
||||
public void testInherited() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/inherited.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("mpp.kt")
|
||||
public void testMpp() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/mpp.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nested.kt")
|
||||
public void testNested() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/nested.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("returnTestResult.kt")
|
||||
public void testReturnTestResult() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/returnTestResult.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/kotlin.test/simple.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("js/js.translator/testData/box/esModules/main")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
Reference in New Issue
Block a user