[JS Test] Support RECOMPILE directive in js box tests in new infrastructure

This commit is contained in:
Dmitriy Novozhilov
2021-10-20 13:04:19 +03:00
committed by Ivan Kylchik
parent 13d3b7c0b8
commit af0e40a0d2
20 changed files with 541 additions and 177 deletions
@@ -66,6 +66,13 @@ class TestRunner(private val testConfiguration: TestConfiguration) {
if (it.shouldSkipTest()) return
}
runTestPipeline(moduleStructure, services)
}
fun runTestPipeline(
moduleStructure: TestModuleStructure,
services: TestServices
) {
val globalMetadataInfoHandler = testConfiguration.testServices.globalMetadataInfoHandler
globalMetadataInfoHandler.parseExistingMetadataInfosFromAllSources()
@@ -103,6 +110,10 @@ class TestRunner(private val testConfiguration: TestConfiguration) {
}
}
reportFailures(services)
}
fun reportFailures(services: TestServices) {
val filteredFailedAssertions = filterFailedExceptions(allFailedExceptions)
filteredFailedAssertions.firstIsInstanceOrNull<WrappedException.FromFacade>()?.let {
throw it
@@ -113,7 +124,7 @@ class TestRunner(private val testConfiguration: TestConfiguration) {
/*
* Returns false if next modules should be not processed
*/
private fun processModule(
fun processModule(
module: TestModule,
dependencyProvider: DependencyProviderImpl
): Boolean {
@@ -12,13 +12,16 @@ abstract class DependencyProvider : TestService {
abstract fun getTestModule(name: String): TestModule
abstract fun <A : ResultingArtifact<A>> getArtifact(module: TestModule, kind: TestArtifactKind<A>): A
abstract fun unregisterAllArtifacts(module: TestModule)
abstract fun copy(): DependencyProvider
}
val TestServices.dependencyProvider: DependencyProvider by TestServices.testServiceAccessor()
class DependencyProviderImpl(
private val testServices: TestServices,
testModules: List<TestModule>
private val testModules: List<TestModule>
) : DependencyProvider() {
private val assertions: Assertions
get() = testServices.assertions
@@ -44,6 +47,16 @@ class DependencyProviderImpl(
if (previousValue != null) error("Artifact with kind $kind already registered for module ${module.name}")
}
override fun unregisterAllArtifacts(module: TestModule) {
artifactsByModule.remove(module)
}
override fun copy(): DependencyProvider {
return DependencyProviderImpl(testServices, testModules).also {
artifactsByModule.putAll(artifactsByModule.mapValues { (_, map) -> map.toMutableMap() })
}
}
private fun <K, V, R> MutableMap<K, MutableMap<V, R>>.getMap(key: K): MutableMap<V, R> {
return getOrPut(key) { mutableMapOf() }
}
@@ -53,11 +53,14 @@ class TestConfigurationBuilder {
lateinit var startingArtifactFactory: (TestModule) -> ResultingArtifact<*>
private val globalDefaultsConfigurators: MutableList<DefaultsProviderBuilder.() -> Unit> = mutableListOf()
private val defaultDirectiveConfigurators: MutableList<RegisteredDirectivesBuilder.() -> Unit> = mutableListOf()
inline fun <reified T : TestService> useAdditionalService(noinline serviceConstructor: (TestServices) -> T) {
useAdditionalService(service(serviceConstructor))
useAdditionalServices(service(serviceConstructor))
}
fun useAdditionalService(serviceRegistrationData: ServiceRegistrationData) {
fun useAdditionalServices(vararg serviceRegistrationData: ServiceRegistrationData) {
additionalServices += serviceRegistrationData
}
@@ -88,7 +91,8 @@ class TestConfigurationBuilder {
configurationsByNegativeTestDataCondition += pattern to configuration
}
inline fun globalDefaults(init: DefaultsProviderBuilder.() -> Unit) {
fun globalDefaults(init: DefaultsProviderBuilder.() -> Unit) {
globalDefaultsConfigurators += init
defaultsProviderBuilder.apply(init)
}
@@ -196,7 +200,8 @@ class TestConfigurationBuilder {
afterAnalysisCheckers += checkers
}
inline fun defaultDirectives(init: RegisteredDirectivesBuilder.() -> Unit) {
fun defaultDirectives(init: RegisteredDirectivesBuilder.() -> Unit) {
defaultDirectiveConfigurators += init
defaultRegisteredDirectivesBuilder.apply(init)
}
@@ -237,9 +242,59 @@ class TestConfigurationBuilder {
directives,
defaultRegisteredDirectivesBuilder.build(),
startingArtifactFactory,
additionalServices
additionalServices,
originalBuilder = ReadOnlyBuilder(this, testDataPath)
)
}
class ReadOnlyBuilder(private val builder: TestConfigurationBuilder, val testDataPath: String) {
val defaultsProviderBuilder: DefaultsProviderBuilder
get() = builder.defaultsProviderBuilder
val assertions: AssertionsService
get() = builder.assertions
val sourcePreprocessors: List<Constructor<SourceFilePreprocessor>>
get() = builder.sourcePreprocessors
val additionalMetaInfoProcessors: List<Constructor<AdditionalMetaInfoProcessor>>
get() = builder.additionalMetaInfoProcessors
val environmentConfigurators: List<Constructor<EnvironmentConfigurator>>
get() = builder.environmentConfigurators
val preAnalysisHandlers: List<Constructor<PreAnalysisHandler>>
get() = builder.preAnalysisHandlers
val additionalSourceProviders: List<Constructor<AdditionalSourceProvider>>
get() = builder.additionalSourceProviders
val moduleStructureTransformers: List<ModuleStructureTransformer>
get() = builder.moduleStructureTransformers
val metaTestConfigurators: List<Constructor<MetaTestConfigurator>>
get() = builder.metaTestConfigurators
val afterAnalysisCheckers: List<Constructor<AfterAnalysisChecker>>
get() = builder.afterAnalysisCheckers
val metaInfoHandlerEnabled: Boolean
get() = builder.metaInfoHandlerEnabled
val directives: List<DirectivesContainer>
get() = builder.directives
val defaultDirectiveConfigurators: List<RegisteredDirectivesBuilder.() -> Unit>
get() = builder.defaultDirectiveConfigurators
val globalDefaultsConfigurators: List<DefaultsProviderBuilder.() -> Unit>
get() = builder.globalDefaultsConfigurators
val configurationsByPositiveTestDataCondition: List<Pair<Regex, TestConfigurationBuilder.() -> Unit>>
get() = builder.configurationsByPositiveTestDataCondition
val configurationsByNegativeTestDataCondition: List<Pair<Regex, TestConfigurationBuilder.() -> Unit>>
get() = builder.configurationsByNegativeTestDataCondition
val additionalServices: List<ServiceRegistrationData>
get() = builder.additionalServices
val compilerConfigurationProvider: ((Disposable, List<EnvironmentConfigurator>) -> CompilerConfigurationProvider)?
get() = builder.compilerConfigurationProvider
val runtimeClasspathProviders: List<Constructor<RuntimeClasspathProvider>>
get() = builder.runtimeClasspathProviders
val testInfo: KotlinTestInfo
get() = builder.testInfo
val startingArtifactFactory: (TestModule) -> ResultingArtifact<*>
get() = builder.startingArtifactFactory
}
}
inline fun testConfiguration(testDataPath: String, init: TestConfigurationBuilder.() -> Unit): TestConfiguration {
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.test.impl
import com.intellij.openapi.Disposable
import org.jetbrains.kotlin.test.*
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.model.ComposedDirectivesContainer
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
@@ -45,12 +46,15 @@ class TestConfigurationImpl(
directives: List<DirectivesContainer>,
override val defaultRegisteredDirectives: RegisteredDirectives,
override val startingArtifactFactory: (TestModule) -> ResultingArtifact<*>,
additionalServices: List<ServiceRegistrationData>
) : TestConfiguration() {
additionalServices: List<ServiceRegistrationData>,
val originalBuilder: TestConfigurationBuilder.ReadOnlyBuilder
) : TestConfiguration(), TestService {
override val rootDisposable: Disposable = TestDisposable()
override val testServices: TestServices = TestServices()
init {
testServices.register(TestConfigurationImpl::class, this)
testServices.register(KotlinTestInfo::class, testInfo)
val runtimeClassPathProviders = runtimeClasspathProviders.map { it.invoke(testServices) }
testServices.register(RuntimeClasspathProvidersContainer::class, RuntimeClasspathProvidersContainer(runtimeClassPathProviders))
@@ -133,3 +137,6 @@ class TestConfigurationImpl(
this.forEach { it.registerDirectivesAndServices() }
}
}
@TestInfrastructureInternals
val TestServices.testConfiguration: TestConfigurationImpl by TestServices.testServiceAccessor()
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.test.model
import org.jetbrains.kotlin.codegen.ClassFileFactory
import org.jetbrains.kotlin.incremental.js.TranslationResultValue
import org.jetbrains.kotlin.ir.backend.js.CompilerResult
import org.jetbrains.kotlin.js.backend.ast.JsProgram
import org.jetbrains.kotlin.js.facade.TranslationResult
@@ -22,9 +23,19 @@ object BinaryArtifacts {
override val kind: BinaryKind<Js>
get() = ArtifactKinds.Js
class OldJsArtifact(override val outputFile: File, val translationResult: TranslationResult) : Js()
open fun unwrap(): Js = this
class OldJsArtifact(override val outputFile: File, val translationResult: TranslationResult) : Js()
class JsIrArtifact(override val outputFile: File, val compilerResult: CompilerResult) : Js()
data class IncrementalJsArtifact(val originalArtifact: Js, val recompiledArtifact: Js) : Js() {
override val outputFile: File
get() = unwrap().outputFile
override fun unwrap(): Js {
return originalArtifact
}
}
}
class Native : ResultingArtifact.Binary<Native>() {
@@ -36,10 +36,6 @@ fun main(args: Array<String>) {
generateTestGroupSuite(args) {
testGroup("js/js.tests/tests-gen", "js/js.translator/testData", testRunnerMethodName = "runTest0") {
testClass<org.jetbrains.kotlin.js.test.semantics.AbstractBoxJsTest> {
model("box/incremental/", pattern = "^([^_](.+))\\.kt$", targetBackend = TargetBackend.JS)
}
testClass<AbstractIrBoxJsTest> {
model("box/", pattern = "^([^_](.+))\\.kt$", targetBackend = TargetBackend.JS_IR)
}
@@ -126,8 +122,8 @@ fun main(args: Array<String>) {
generateTestGroupSuiteWithJUnit5(args) {
testGroup("js/js.tests/tests-gen", "js/js.translator/testData", testRunnerMethodName = "runTest0") {
testClass<org.jetbrains.kotlin.js.testNew.AbstractBoxJsTest> {
model("box/", pattern = "^([^_](.+))\\.kt$", excludeDirs = listOf("incremental"))
testClass<AbstractBoxJsTest> {
model("box/", pattern = "^([^_](.+))\\.kt$")
}
testClass<AbstractSourceMapGenerationSmokeTest> {
@@ -1,16 +0,0 @@
/*
* Copyright 2010-2020 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.js.test.semantics
import org.jetbrains.kotlin.js.test.BasicBoxTest
abstract class AbstractBoxJsTest : BasicBoxTest(
TEST_DATA_DIR_PATH + "box/",
"box/"
) {
override val runMinifierByDefault: Boolean = true
}
@@ -5,10 +5,8 @@
package org.jetbrains.kotlin.js.testNew
import org.jetbrains.kotlin.js.testNew.handlers.JsArtifactsDumpHandler
import org.jetbrains.kotlin.js.testNew.handlers.JsBoxRunner
import org.jetbrains.kotlin.js.testNew.handlers.JsMinifierRunner
import org.jetbrains.kotlin.js.testNew.handlers.NodeJsGeneratorHandler
import org.jetbrains.kotlin.js.testNew.handlers.*
import org.jetbrains.kotlin.js.testNew.utils.JsIncrementalEnvironmentConfigurator
import org.jetbrains.kotlin.platform.js.JsPlatforms
import org.jetbrains.kotlin.test.Constructor
import org.jetbrains.kotlin.test.TargetBackend
@@ -37,6 +35,7 @@ abstract class AbstractJsBlackBoxCodegenTestBase<R : ResultingArtifact.FrontendO
abstract val frontendFacade: Constructor<FrontendFacade<R>>
abstract val frontendToBackendConverter: Constructor<Frontend2BackendConverter<R, I>>
abstract val backendFacade: Constructor<BackendFacade<I, BinaryArtifacts.Js>>
abstract val recompileFacade: Constructor<AbstractTestFacade<BinaryArtifacts.Js, BinaryArtifacts.Js>>
override fun TestConfigurationBuilder.configuration() {
globalDefaults {
@@ -58,6 +57,7 @@ abstract class AbstractJsBlackBoxCodegenTestBase<R : ResultingArtifact.FrontendO
useConfigurators(
::CommonEnvironmentConfigurator,
::JsEnvironmentConfigurator,
::JsIncrementalEnvironmentConfigurator
)
useAdditionalSourceProviders(
@@ -80,12 +80,14 @@ abstract class AbstractJsBlackBoxCodegenTestBase<R : ResultingArtifact.FrontendO
irHandlersStep()
facadeStep(backendFacade)
facadeStep(recompileFacade)
jsArtifactsHandlersStep {
useHandlers(
::JsBoxRunner,
::NodeJsGeneratorHandler,
::JsMinifierRunner,
::JsArtifactsDumpHandler,
::JsRecompiledArtifactsIdentityHandler
)
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.js.testNew
import org.jetbrains.kotlin.js.testNew.converters.ClassicJsBackendFacade
import org.jetbrains.kotlin.js.testNew.converters.RecompileModuleJsBackendFacade
import org.jetbrains.kotlin.js.testNew.handlers.*
import org.jetbrains.kotlin.test.Constructor
import org.jetbrains.kotlin.test.TargetBackend
@@ -34,6 +35,9 @@ abstract class AbstractJsTest(
override val backendFacade: Constructor<BackendFacade<ClassicBackendInput, BinaryArtifacts.Js>>
get() = ::ClassicJsBackendFacade
override val recompileFacade: Constructor<AbstractTestFacade<BinaryArtifacts.Js, BinaryArtifacts.Js>>
get() = { RecompileModuleJsBackendFacade(it, frontendFacade, frontendToBackendConverter) }
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
with(builder) {
@@ -7,15 +7,16 @@ package org.jetbrains.kotlin.js.testNew.converters
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.text.StringUtil
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import org.jetbrains.kotlin.cli.common.output.writeAllTo
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumerImpl
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.facade.K2JSTranslator
import org.jetbrains.kotlin.js.facade.MainCallParameters
import org.jetbrains.kotlin.js.facade.TranslationResult
import org.jetbrains.kotlin.js.facade.TranslationUnit
import org.jetbrains.kotlin.js.testNew.utils.JsClassicIncrementalDataProvider
import org.jetbrains.kotlin.js.testNew.utils.jsClassicIncrementalDataProvider
import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.test.backend.classic.ClassicBackendFacade
import org.jetbrains.kotlin.test.backend.classic.ClassicBackendInput
@@ -23,21 +24,26 @@ import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.model.ArtifactKinds
import org.jetbrains.kotlin.test.model.BinaryArtifacts
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.ServiceRegistrationData
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import java.io.ByteArrayOutputStream
import org.jetbrains.kotlin.test.services.service
import java.io.File
import java.io.PrintStream
import java.nio.charset.Charset
class ClassicJsBackendFacade(
testServices: TestServices
testServices: TestServices,
val incrementalCompilationEnabled: Boolean
) : ClassicBackendFacade<BinaryArtifacts.Js>(testServices, ArtifactKinds.Js) {
companion object {
const val KOTLIN_TEST_INTERNAL = "\$kotlin_test_internal\$"
}
constructor(testServices: TestServices) : this(testServices, incrementalCompilationEnabled = false)
override val additionalServices: List<ServiceRegistrationData>
get() = listOf(service(::JsClassicIncrementalDataProvider))
private fun wrapWithModuleEmulationMarkers(content: String, moduleKind: ModuleKind, moduleId: String): String {
val escapedModuleId = StringUtil.escapeStringCharacters(moduleId)
@@ -57,13 +63,25 @@ class ClassicJsBackendFacade(
}
}
override fun transform(module: TestModule, inputArtifact: ClassicBackendInput): BinaryArtifacts.Js? {
override fun transform(module: TestModule, inputArtifact: ClassicBackendInput): BinaryArtifacts.Js {
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
val (psiFiles, analysisResult, project, _) = inputArtifact
// TODO how to reuse this config from frontend
val jsConfig = JsEnvironmentConfigurator.createJsConfig(project, configuration)
val units = psiFiles.map(TranslationUnit::SourceFile)
val unitsByPath: MutableMap<String, TranslationUnit> = psiFiles.associateTo(mutableMapOf()) {
(it.virtualFile.canonicalPath ?: "") to TranslationUnit.SourceFile(it)
}
if (incrementalCompilationEnabled) {
val incrementalData = testServices.jsClassicIncrementalDataProvider.getIncrementalData(module)
for ((file, data) in incrementalData.translatedFiles) {
unitsByPath[file.canonicalPath] = TranslationUnit.BinaryAst(data.binaryAst, data.inlineData)
}
}
val units = unitsByPath.entries.sortedBy { it.key }.map { it.value }
val mainCallParameters = when (JsEnvironmentConfigurationDirectives.CALL_MAIN) {
in module.directives -> MainCallParameters.mainWithArguments(listOf())
else -> MainCallParameters.noCall()
@@ -74,6 +92,22 @@ class ClassicJsBackendFacade(
JsEnvironmentConfigurator.Companion.ExceptionThrowingReporter, units, mainCallParameters, analysisResult as? JsAnalysisResult
)
if (!incrementalCompilationEnabled) {
jsConfig.configuration[JSConfigurationKeys.INCREMENTAL_RESULTS_CONSUMER]?.let {
val incrementalData = JsClassicIncrementalDataProvider.IncrementalData()
val incrementalService = it as IncrementalResultsConsumerImpl
for ((srcFile, data) in incrementalService.packageParts) {
incrementalData.translatedFiles[srcFile] = data
}
incrementalData.packageMetadata += incrementalService.packageMetadata
incrementalData.header = incrementalService.headerMetadata
testServices.jsClassicIncrementalDataProvider.recordIncrementalData(module, incrementalData)
}
}
val outputFile = File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name) + ".js")
if (translationResult !is TranslationResult.Success) {
return BinaryArtifacts.Js.OldJsArtifact(outputFile, translationResult)
@@ -92,4 +126,4 @@ class ClassicJsBackendFacade(
return BinaryArtifacts.Js.OldJsArtifact(outputFile, translationResult)
}
}
}
@@ -0,0 +1,99 @@
/*
* Copyright 2010-2021 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.js.testNew.converters
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.js.parser.sourcemaps.SourceMapParser
import org.jetbrains.kotlin.js.parser.sourcemaps.SourceMapSuccess
import org.jetbrains.kotlin.js.testNew.utils.jsClassicIncrementalDataProvider
import org.jetbrains.kotlin.test.*
import org.jetbrains.kotlin.test.backend.classic.ClassicBackendInput
import org.jetbrains.kotlin.test.builders.testConfiguration
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.RECOMPILE
import org.jetbrains.kotlin.test.impl.testConfiguration
import org.jetbrains.kotlin.test.model.*
import org.jetbrains.kotlin.test.services.*
import org.jetbrains.kotlin.test.services.impl.TestModuleStructureImpl
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.PrintStream
import java.nio.charset.Charset
@Suppress("warnings")
class RecompileModuleJsBackendFacade<R : ResultingArtifact.FrontendOutput<R>>(
val testServices: TestServices,
private val frontendFacade: Constructor<FrontendFacade<R>>,
private val frontend2BackendConverter: Constructor<Frontend2BackendConverter<R, ClassicBackendInput>>
) : AbstractTestFacade<BinaryArtifacts.Js, BinaryArtifacts.Js>() {
override val inputKind: ArtifactKinds.Js
get() = ArtifactKinds.Js
override val outputKind: ArtifactKinds.Js
get() = ArtifactKinds.Js
@OptIn(TestInfrastructureInternals::class)
override fun transform(module: TestModule, inputArtifact: BinaryArtifacts.Js): BinaryArtifacts.Js {
val filesToRecompile = module.files.filter { RECOMPILE in it.directives }
if (filesToRecompile.isEmpty()) return inputArtifact
val builder = testServices.testConfiguration.originalBuilder
val incrementalConfiguration = testConfiguration(builder.testDataPath) {
assertions = builder.assertions
testInfo = builder.testInfo
startingArtifactFactory = builder.startingArtifactFactory
useSourcePreprocessor(*builder.sourcePreprocessors.toTypedArray())
useMetaInfoProcessors(*builder.additionalMetaInfoProcessors.toTypedArray())
useConfigurators(*builder.environmentConfigurators.toTypedArray())
useDirectives(*builder.directives.toTypedArray())
useAdditionalServices(*builder.additionalServices.toTypedArray())
builder.globalDefaultsConfigurators.forEach { globalDefaults(it) }
builder.defaultDirectiveConfigurators.forEach { defaultDirectives(it) }
builder.configurationsByPositiveTestDataCondition.forEach { (regex, init) -> forTestsMatching(regex, init) }
builder.configurationsByNegativeTestDataCondition.forEach { (regex, init) -> forTestsNotMatching(regex, init) }
facadeStep(frontendFacade)
facadeStep(frontend2BackendConverter)
facadeStep { ClassicJsBackendFacade(it, incrementalCompilationEnabled = true) }
}
val moduleStructure = testServices.moduleStructure
val incrementalModule = module.copy(files = filesToRecompile)
val incrementalModuleStructure = TestModuleStructureImpl(
moduleStructure.modules.map {
if (it != module) return@map it
else incrementalModule
},
moduleStructure.originalTestDataFiles
)
val incrementalRunner = TestRunner(incrementalConfiguration)
val incrementalDependencyProvider = testServices.dependencyProvider.copy().also {
it.unregisterAllArtifacts(module)
} as DependencyProviderImpl
val incrementalServices = incrementalConfiguration.testServices
incrementalServices.registerDependencyProvider(incrementalDependencyProvider)
incrementalServices.register(TestModuleStructure::class, incrementalModuleStructure)
incrementalServices.register(TemporaryDirectoryManager::class, testServices.temporaryDirectoryManager)
val incrementalData = testServices.jsClassicIncrementalDataProvider.getIncrementalData(module).copy()
for (testFile in filesToRecompile) {
incrementalData.translatedFiles.remove(File("/${testFile.relativePath}"))
}
incrementalServices.jsClassicIncrementalDataProvider.recordIncrementalData(
module,
incrementalData
)
incrementalRunner.processModule(incrementalModule, incrementalDependencyProvider)
incrementalRunner.reportFailures(incrementalServices)
val incrementalArtifact = incrementalDependencyProvider.getArtifact(incrementalModule, ArtifactKinds.Js)
return BinaryArtifacts.Js.IncrementalJsArtifact(inputArtifact, incrementalArtifact)
}
override fun shouldRunAnalysis(module: TestModule): Boolean {
return module.targetBackend == TargetBackend.JS && module.files.any { RECOMPILE in it.directives }
}
}
@@ -25,7 +25,7 @@ class JsAstHandler(testServices: TestServices) : JsBinaryArtifactHandler(testSer
override fun processModule(module: TestModule, info: BinaryArtifacts.Js) {
val ktFiles = module.files.filter { it.isKtFile }.map { it.originalContent }
val result = (info as? BinaryArtifacts.Js.OldJsArtifact)?.translationResult
val result = (info.unwrap() as? BinaryArtifacts.Js.OldJsArtifact)?.translationResult
?: throw IllegalArgumentException("JsBoxRunner suppose to work only with old js backend")
processJsProgram((result as TranslationResult.Success).program, ktFiles, module.targetBackend!!) {
testServices.assertions.fail { it }
@@ -59,4 +59,4 @@ class JsAstHandler(testServices: TestServices) : JsBinaryArtifactHandler(testSer
})
}
}
}
}
@@ -0,0 +1,70 @@
/*
* Copyright 2010-2021 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.js.testNew.handlers
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.js.parser.sourcemaps.SourceMapParser
import org.jetbrains.kotlin.js.parser.sourcemaps.SourceMapSuccess
import org.jetbrains.kotlin.test.backend.handlers.JsBinaryArtifactHandler
import org.jetbrains.kotlin.test.model.BinaryArtifacts.Js
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.PrintStream
import java.nio.charset.Charset
class JsRecompiledArtifactsIdentityHandler(testServices: TestServices) : JsBinaryArtifactHandler(testServices) {
override fun processModule(module: TestModule, info: Js) {
if (info !is Js.IncrementalJsArtifact) return
val (originalArtifact, incrementalArtifact) = info
when {
originalArtifact is Js.OldJsArtifact && incrementalArtifact is Js.OldJsArtifact -> {
compareArtifacts(originalArtifact, incrementalArtifact)
}
else -> assertions.fail {
"""
Incompatible types of original and incremental artifacts:
original: ${originalArtifact::class}
incremental: ${incrementalArtifact::class}
""".trimIndent()
}
}
}
private fun compareArtifacts(originalArtifact: Js.OldJsArtifact, incrementalArtifact: Js.OldJsArtifact) {
val originalSourceMap = FileUtil.loadFile(File(originalArtifact.outputFile.parentFile, originalArtifact.outputFile.name + ".map"))
val recompiledSourceMap =
removeRecompiledSuffix(
FileUtil.loadFile(File(incrementalArtifact.outputFile.parentFile, incrementalArtifact.outputFile.name + ".map"))
)
if (originalSourceMap != recompiledSourceMap) {
val originalSourceMapParse = SourceMapParser.parse(originalSourceMap)
val recompiledSourceMapParse = SourceMapParser.parse(recompiledSourceMap)
if (originalSourceMapParse is SourceMapSuccess && recompiledSourceMapParse is SourceMapSuccess) {
testServices.assertions.assertEquals(
originalSourceMapParse.toDebugString(),
recompiledSourceMapParse.toDebugString(),
) { "Source map file changed after recompilation" }
}
testServices.assertions.assertEquals(originalSourceMap, recompiledSourceMap) { "Source map file changed after recompilation" }
}
}
private fun SourceMapSuccess.toDebugString(): String {
val out = ByteArrayOutputStream()
PrintStream(out).use { value.debug(it) }
return String(out.toByteArray(), Charset.forName("UTF-8"))
}
private fun removeRecompiledSuffix(text: String): String = text.replace("-recompiled.js", ".js")
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {}
}
@@ -34,7 +34,7 @@ class JsSourceMapHandler(testServices: TestServices) : JsBinaryArtifactHandler(t
override fun processModule(module: TestModule, info: BinaryArtifacts.Js) {
val outputFile = File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name))
val result = (info as? BinaryArtifacts.Js.OldJsArtifact)?.translationResult
val result = (info.unwrap() as? BinaryArtifacts.Js.OldJsArtifact)?.translationResult
?: throw IllegalArgumentException("JsBoxRunner suppose to work only with old js backend")
val remap = JsEnvironmentConfigurationDirectives.SKIP_SOURCEMAP_REMAPPING !in module.directives
checkSourceMap(outputFile, (result as TranslationResult.Success).program, remap) { expected, actual ->
@@ -98,4 +98,4 @@ class JsSourceMapHandler(testServices: TestServices) : JsBinaryArtifactHandler(t
})
}
}
}
}
@@ -21,7 +21,7 @@ class JsTranslationResultHandler(testServices: TestServices) : JsBinaryArtifactH
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {}
override fun processModule(module: TestModule, info: BinaryArtifacts.Js) {
val result = (info as? BinaryArtifacts.Js.OldJsArtifact)?.translationResult
val result = (info.unwrap() as? BinaryArtifacts.Js.OldJsArtifact)?.translationResult
?: throw IllegalArgumentException("JsTranslationResultHandler suppose to work only with old js backend")
if (result !is TranslationResult.Success) {
@@ -32,4 +32,4 @@ class JsTranslationResultHandler(testServices: TestServices) : JsBinaryArtifactH
throw AssertionError("The following errors occurred compiling test:\n$messages")
}
}
}
}
@@ -0,0 +1,44 @@
/*
* Copyright 2010-2021 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.js.testNew.utils
import org.jetbrains.kotlin.incremental.js.TranslationResultValue
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestService
import org.jetbrains.kotlin.test.services.TestServices
import java.io.File
class JsClassicIncrementalDataProvider(private val testServices: TestServices) : TestService {
class IncrementalData(
var header: ByteArray? = null,
val translatedFiles: MutableMap<File, TranslationResultValue> = hashMapOf(),
val packageMetadata: MutableMap<String, ByteArray> = hashMapOf()
) {
fun copy(): IncrementalData {
return IncrementalData(
header?.clone(),
translatedFiles.toMutableMap(),
packageMetadata.toMutableMap()
)
}
}
private val cache: MutableMap<TestModule, IncrementalData> = mutableMapOf()
fun recordIncrementalData(module: TestModule, incrementalData: IncrementalData) {
cache[module] = incrementalData
}
fun getIncrementalData(module: TestModule): IncrementalData {
return cache.getValue(module)
}
fun getIncrementalDataIfAny(module: TestModule): IncrementalData? {
return cache[module]
}
}
val TestServices.jsClassicIncrementalDataProvider: JsClassicIncrementalDataProvider by TestServices.testServiceAccessor()
@@ -0,0 +1,39 @@
/*
* Copyright 2010-2021 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.js.testNew.utils
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.incremental.js.IncrementalDataProviderImpl
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumerImpl
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.EnvironmentConfigurator
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.utils.JsMetadataVersion
class JsIncrementalEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigurator(testServices) {
override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule) {
if (module.files.any { JsEnvironmentConfigurationDirectives.RECOMPILE in it.directives }) {
val incrementalData = testServices.jsClassicIncrementalDataProvider.getIncrementalDataIfAny(module)
val header = incrementalData?.header
if (header != null) {
configuration.put(
JSConfigurationKeys.INCREMENTAL_DATA_PROVIDER,
IncrementalDataProviderImpl(
header,
incrementalData.translatedFiles,
JsMetadataVersion.INSTANCE.toArray(),
incrementalData.packageMetadata,
emptyMap()
)
)
}
configuration.put(JSConfigurationKeys.INCREMENTAL_RESULTS_CONSUMER, IncrementalResultsConsumerImpl())
}
}
}
@@ -1,122 +0,0 @@
/*
* Copyright 2010-2021 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.js.test.semantics;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("js/js.translator/testData/box/incremental")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class BoxJsTestGenerated extends AbstractBoxJsTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
public void testAllFilesPresentInIncremental() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/incremental"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS, true);
}
@TestMetadata("catchScope.kt")
public void testCatchScope() throws Exception {
runTest("js/js.translator/testData/box/incremental/catchScope.kt");
}
@TestMetadata("classReferencingClass.kt")
public void testClassReferencingClass() throws Exception {
runTest("js/js.translator/testData/box/incremental/classReferencingClass.kt");
}
@TestMetadata("coroutines.kt")
public void testCoroutines() throws Exception {
runTest("js/js.translator/testData/box/incremental/coroutines.kt");
}
@TestMetadata("defaultArguments.kt")
public void testDefaultArguments() throws Exception {
runTest("js/js.translator/testData/box/incremental/defaultArguments.kt");
}
@TestMetadata("enumUsage.kt")
public void testEnumUsage() throws Exception {
runTest("js/js.translator/testData/box/incremental/enumUsage.kt");
}
@TestMetadata("exportedPackage.kt")
public void testExportedPackage() throws Exception {
runTest("js/js.translator/testData/box/incremental/exportedPackage.kt");
}
@TestMetadata("functionReferencingClass.kt")
public void testFunctionReferencingClass() throws Exception {
runTest("js/js.translator/testData/box/incremental/functionReferencingClass.kt");
}
@TestMetadata("inline.kt")
public void testInline() throws Exception {
runTest("js/js.translator/testData/box/incremental/inline.kt");
}
@TestMetadata("inlineLambda.kt")
public void testInlineLambda() throws Exception {
runTest("js/js.translator/testData/box/incremental/inlineLambda.kt");
}
@TestMetadata("inlineModuleVariable.kt")
public void testInlineModuleVariable() throws Exception {
runTest("js/js.translator/testData/box/incremental/inlineModuleVariable.kt");
}
@TestMetadata("inlineSuspendFun.kt")
public void testInlineSuspendFun() throws Exception {
runTest("js/js.translator/testData/box/incremental/inlineSuspendFun.kt");
}
@TestMetadata("jsModule.kt")
public void testJsModule() throws Exception {
runTest("js/js.translator/testData/box/incremental/jsModule.kt");
}
@TestMetadata("multipleExport.kt")
public void testMultipleExport() throws Exception {
runTest("js/js.translator/testData/box/incremental/multipleExport.kt");
}
@TestMetadata("multipleReimport.kt")
public void testMultipleReimport() throws Exception {
runTest("js/js.translator/testData/box/incremental/multipleReimport.kt");
}
@TestMetadata("packagesWithSameName.kt")
public void testPackagesWithSameName() throws Exception {
runTest("js/js.translator/testData/box/incremental/packagesWithSameName.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("js/js.translator/testData/box/incremental/simple.kt");
}
@TestMetadata("sourceMapSourceEmbedding.kt")
public void testSourceMapSourceEmbedding() throws Exception {
runTest("js/js.translator/testData/box/incremental/sourceMapSourceEmbedding.kt");
}
@TestMetadata("syntheticStatement.kt")
public void testSyntheticStatement() throws Exception {
runTest("js/js.translator/testData/box/incremental/syntheticStatement.kt");
}
}
@@ -22,7 +22,7 @@ import java.util.regex.Pattern;
public class BoxJsTestGenerated extends AbstractBoxJsTest {
@Test
public void testAllFilesPresentInBox() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS, true, "incremental");
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS, true);
}
@Nested
@@ -3981,6 +3981,124 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
}
}
@Nested
@TestMetadata("js/js.translator/testData/box/incremental")
@TestDataPath("$PROJECT_ROOT")
public class Incremental {
@Test
public void testAllFilesPresentInIncremental() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/incremental"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS, true);
}
@Test
@TestMetadata("catchScope.kt")
public void testCatchScope() throws Exception {
runTest("js/js.translator/testData/box/incremental/catchScope.kt");
}
@Test
@TestMetadata("classReferencingClass.kt")
public void testClassReferencingClass() throws Exception {
runTest("js/js.translator/testData/box/incremental/classReferencingClass.kt");
}
@Test
@TestMetadata("coroutines.kt")
public void testCoroutines() throws Exception {
runTest("js/js.translator/testData/box/incremental/coroutines.kt");
}
@Test
@TestMetadata("defaultArguments.kt")
public void testDefaultArguments() throws Exception {
runTest("js/js.translator/testData/box/incremental/defaultArguments.kt");
}
@Test
@TestMetadata("enumUsage.kt")
public void testEnumUsage() throws Exception {
runTest("js/js.translator/testData/box/incremental/enumUsage.kt");
}
@Test
@TestMetadata("exportedPackage.kt")
public void testExportedPackage() throws Exception {
runTest("js/js.translator/testData/box/incremental/exportedPackage.kt");
}
@Test
@TestMetadata("functionReferencingClass.kt")
public void testFunctionReferencingClass() throws Exception {
runTest("js/js.translator/testData/box/incremental/functionReferencingClass.kt");
}
@Test
@TestMetadata("inline.kt")
public void testInline() throws Exception {
runTest("js/js.translator/testData/box/incremental/inline.kt");
}
@Test
@TestMetadata("inlineLambda.kt")
public void testInlineLambda() throws Exception {
runTest("js/js.translator/testData/box/incremental/inlineLambda.kt");
}
@Test
@TestMetadata("inlineModuleVariable.kt")
public void testInlineModuleVariable() throws Exception {
runTest("js/js.translator/testData/box/incremental/inlineModuleVariable.kt");
}
@Test
@TestMetadata("inlineSuspendFun.kt")
public void testInlineSuspendFun() throws Exception {
runTest("js/js.translator/testData/box/incremental/inlineSuspendFun.kt");
}
@Test
@TestMetadata("jsModule.kt")
public void testJsModule() throws Exception {
runTest("js/js.translator/testData/box/incremental/jsModule.kt");
}
@Test
@TestMetadata("multipleExport.kt")
public void testMultipleExport() throws Exception {
runTest("js/js.translator/testData/box/incremental/multipleExport.kt");
}
@Test
@TestMetadata("multipleReimport.kt")
public void testMultipleReimport() throws Exception {
runTest("js/js.translator/testData/box/incremental/multipleReimport.kt");
}
@Test
@TestMetadata("packagesWithSameName.kt")
public void testPackagesWithSameName() throws Exception {
runTest("js/js.translator/testData/box/incremental/packagesWithSameName.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("js/js.translator/testData/box/incremental/simple.kt");
}
@Test
@TestMetadata("sourceMapSourceEmbedding.kt")
public void testSourceMapSourceEmbedding() throws Exception {
runTest("js/js.translator/testData/box/incremental/sourceMapSourceEmbedding.kt");
}
@Test
@TestMetadata("syntheticStatement.kt")
public void testSyntheticStatement() throws Exception {
runTest("js/js.translator/testData/box/incremental/syntheticStatement.kt");
}
}
@Nested
@TestMetadata("js/js.translator/testData/box/inheritance")
@TestDataPath("$PROJECT_ROOT")
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.test.backend.ir.JvmIrBackendFacade
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.builders.configureClassicFrontendHandlersStep
import org.jetbrains.kotlin.test.builders.configureFirHandlersStep
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.REQUIRES_SEPARATE_PROCESS
import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives.DIAGNOSTICS
import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives.REPORT_ONLY_EXPLICITLY_DEFINED_DEBUG_INFO
@@ -71,7 +70,7 @@ abstract class AbstractParcelizeBoxTestBase<R : ResultingArtifact.FrontendOutput
useConfigurators(::ParcelizeEnvironmentConfigurator)
useAdditionalSourceProviders(::ParcelizeUtilSourcesProvider)
useAdditionalService(service<JvmBoxMainClassProvider>(::ParcelizeMainClassProvider))
useAdditionalServices(service<JvmBoxMainClassProvider>(::ParcelizeMainClassProvider))
useAfterAnalysisCheckers(::BlackBoxCodegenSuppressor)